# What changed in astroid

> 17 changes in astroid 4 from its official release notes, upgrade guides and advisories: 1 breaking. Each one cited. Sources checked 2026-10-25. HTML: https://unstale.sh/pypi/astroid/

To see which of these apply to a repository, run `npx @unstale/cli init` in it.

## astroid 4

### Breaking changes

- A function whose body is only ... is inferred to return Uninferable instead of None, matching a function whose body is only pass. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)

### Fixes and other changes

- No longer raises IndexError when a keyword-only argument repeats the name of *args or **kwargs. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)
- ValueError during comparison inference is caught and returns Uninferable instead of raising an uncaught exception. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)
- Introspecting a live class that exposes itself or a sibling class as one of its own attributes no longer loops infinitely. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)
- Building a module from a live object that holds a container containing itself no longer raises RecursionError. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)
- Inferring random.sample() on a sequence whose elements are inferred as Instance no longer crashes with TypeError. (4.3.4) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.4)
- Fixes a TypeError when __class_getitem__ is uninferable. (4.3.3) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.3)
- Inferred concatenations preserve their length when an element has multiple possible values; ambiguous or uninferable elements are represented as unknown instead of expanded into multiple items. (4.3.3) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.3)
- Fixes an AssertionError when inferring Class.__bases__, which previously returned a parentless Tuple. (4.3.3) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.3)
- An exception instance's args attribute is inferred as a tuple instance of unknown contents rather than a known empty tuple, so unpacking no longer looks unbalanced. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Returns None instead of raising AttributeError for a class whose PEP 695 type parameter is literally named __slots__. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Inference falls back to its default instead of crashing when a type name or field name contains str.format markup. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Inference of an f-string or str.format call with an out-of-range c format-spec code point now yields Uninferable instead of crashing. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Inference falls back to its default instead of crashing when a type name or field name contains str.format markup. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Functional NewType names that are not identifiers are assigned verbatim to the synthesized class, rather than spliced into its source. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Raises InferenceError instead of crashing with IndexError when called without a positional metaclass argument, during module building and call inference. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
- Functional TypeVar names that are not identifiers are assigned verbatim to the synthesized class, rather than spliced into its source. (4.3.2) — [release notes](https://github.com/pylint-dev/astroid/releases/tag/v4.3.2)
