pydantic/pydantic · error · ValueError

"RootModel.__init__" accepts either a single positional argu

Error message

"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments

What it means

RootModel.__init__ takes either a single positional `root` argument OR arbitrary keyword arguments (which become the root dict). Passing BOTH a positional root and keyword data is ambiguous, so ValueError is raised. When kwargs are given, root must be unset.

Source

Thrown at pydantic/root_model.py:66

    __pydantic_root_model__ = True
    __pydantic_private__ = None
    __pydantic_extra__ = None

    root: RootModelRootType

    def __init_subclass__(cls, **kwargs):
        extra = cls.model_config.get('extra')
        if extra is not None:
            raise PydanticUserError(
                "`RootModel` does not support setting `model_config['extra']`", code='root-model-extra'
            )
        super().__init_subclass__(**kwargs)

    def __init__(self, /, root: RootModelRootType = PydanticUndefined, **data) -> None:  # type: ignore
        __tracebackhide__ = True
        if data:
            if root is not PydanticUndefined:
                raise ValueError(
                    '"RootModel.__init__" accepts either a single positional argument or arbitrary keyword arguments'
                )
            root = data  # type: ignore
        self.__pydantic_validator__.validate_python(root, self_instance=self)

    __init__.__pydantic_base_init__ = True  # pyright: ignore[reportFunctionMemberAccess]

    @classmethod
    def model_construct(cls, root: RootModelRootType, _fields_set: set[str] | None = None) -> Self:  # type: ignore
        """Create a new model using the provided root object and update fields set.

        Args:
            root: The root object of the model.
            _fields_set: The set of fields to be updated.

        Returns:
            The new model.

View on GitHub (pinned to 2e5f0e2b42)

Solutions

  1. Pass either positional root OR keyword arguments, not both.
  2. For dict-root models, build the dict first then pass it positionally: MyRoot({'a': 1}).
  3. Adjust generic factory code to choose one form based on the model kind.

Example fix

# before
m = MyRoot({'a': 1}, b=2)
# after
m = MyRoot({'a': 1, 'b': 2})
# or
m = MyRoot(a=1, b=2)
Defensive patterns

Strategy: validation

Validate before calling

def build_root_model(cls, root=..., **kwargs):
    if root is not ... and kwargs:
        raise ValueError('pass either positional root or kwargs, not both')
    return cls(root) if root is not ... else cls(**kwargs)

Type guard

def root_init_args_valid(root_provided: bool, has_kwargs: bool) -> bool:
    return not (root_provided and has_kwargs)

Try / catch

try:
    m = MyRoot(data, **extra)
except ValueError as e:
    if 'RootModel.__init__' in str(e):
        m = MyRoot({**data, **extra})  # merge and retry

Prevention

When it happens

Trigger: MyRoot({'a': 1}, b=2); instantiating a RootModel[dict] with both a mapping positionally and keyword fields; generic factory code that always passes a dict plus kwargs.

Common situations: Programmatic construction that forwards both *args and **kwargs; migrating a BaseModel call site to a RootModel.

Related errors


AI-assisted analysis of pydantic/pydantic@2e5f0e2b42 (2026-08-04). Data as JSON: /data/errors/b989d356bb8a8835.json. Report an issue: GitHub.