oraios/serena · error

The given package object {package_or_version} has no __versi

Error message

The given package object {package_or_version} has no __version__ attribute

What it means

Version's __init__ accepts either a version string or a package object; when a package object is passed but getattr(obj, '__version__') returns None, it raises claiming the object has no __version__ attribute. This guards against constructing a Version from an object with a missing/None version metadata field.

Source

Thrown at src/serena/util/version.py:19

class Version:
    """
    Represents a version, specifically the numeric components of a version string.

    Suffixes like "rc1" or "-dev" are ignored, i.e. for a version string like "1.2.3rc1",
    the components are [1, 2, 3].
    """

    def __init__(self, package_or_version: object | str):
        """
        :param package_or_version: a package object (with a `__version__` attribute) or a version string like "1.2.3".
            If a version contains a suffix (like "1.2.3rc1" or "1.2.3-dev"), the suffix is ignored.
        """
        if isinstance(package_or_version, str):
            version_string = package_or_version
        elif hasattr(package_or_version, "__version__"):
            package_version_string = getattr(package_or_version, "__version__", None)
            if package_version_string is None:
                raise ValueError(f"The given package object {package_or_version} has no __version__ attribute")
            version_string = package_version_string
        else:
            raise ValueError("The given argument must be either a version string or a package object with a __version__ attribute")
        self.version_string = version_string
        self.components = self._get_version_components(version_string)

    def __repr__(self) -> str:
        return self.version_string

    @staticmethod
    def _get_version_components(version_string: str) -> list[int]:
        components = version_string.split(".")
        int_components = []
        for c in components:
            num_str = ""
            for ch in c:
                if ch.isdigit():
                    num_str += ch

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Pass the version string directly: Version('1.2.3') instead of Version(module)
  2. Ensure the package's __version__ is set (proper install/metadata generation)
  3. Check with getattr(mod, '__version__', None) before constructing and handle None

Example fix

// before
Version(some_pkg)  # some_pkg.__version__ is None
// after
ver = getattr(some_pkg, '__version__', None)
if ver is None:
    ver = importlib.metadata.version('some-pkg')
Version(ver)
Defensive patterns

Strategy: type-guard

Validate before calling

ver = getattr(pkg, '__version__', None)
if ver is None:
    ver = importlib.metadata.version(pkg.__name__)
Version(ver)

Type guard

def has_version(obj: object) -> TypeGuard[object]:
    return getattr(obj, '__version__', None) is not None

Try / catch

try:
    v = Version(pkg_or_str)
except ValueError as e:
    if 'has no __version__' in str(e):
        v = Version(importlib.metadata.version('the-package'))
    else:
        raise

Prevention

When it happens

Trigger: Passing a module or object where __version__ exists but is explicitly None (e.g. a package whose metadata wasn't populated), so hasattr passes but the value is None.

Common situations: Namespace packages or locally imported stubs lacking version metadata; packages installed without proper metadata; passing a wrapper class instead of the module itself.

Related errors


AI-assisted analysis of oraios/serena@7fcbca7e62 (2026-08-29). Data as JSON: /api/errors/36bd4c61cf7392ad. Report an issue: GitHub.