oraios/serena · error

The given argument must be either a version string or a pack

Error message

The given argument must be either a version string or a package object with a __version__ attribute

What it means

Version's __init__ also raises when the argument is neither a string nor an object that has a __version__ attribute at all. It tells the caller the input type is wrong — only version strings or package-like objects are supported.

Source

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

    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
                else:
                    break
            if num_str == "":

View on GitHub (pinned to 7fcbca7e62)

Solutions

  1. Pass a version string: Version('2.1.0')
  2. Pass the actual module object (import mypkg; Version(mypkg)) which carries __version__
  3. Coerce other formats to str first, e.g. Version('.'.join(map(str, ver_tuple)))

Example fix

// before
Version((1, 4, 2))  # tuple, not supported
// after
Version('.'.join(map(str, (1, 4, 2))))  # '1.4.2'
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(arg, str) and not hasattr(arg, '__version__'):
    raise TypeError('Version() needs a str or an object with __version__')

Type guard

def is_version_input(arg: object) -> TypeGuard[Union[str, object]]:
    return isinstance(arg, str) or hasattr(arg, '__version__')

Try / catch

try:
    v = Version(arg)
except ValueError as e:
    if 'must be either a version string' in str(e):
        v = Version(str(arg))
    else:
        raise

Prevention

When it happens

Trigger: Passing an int, a Version instance of another library, a dict, or an object without __version__ (e.g. a plain class or a function) to Version(...).

Common situations: Confusing a package's main class with its module; passing version tuples/ints from other tooling; refactors that changed the argument from a string to an object.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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