PrefectHQ/fastmcp · error

Cannot specify both 'default' and 'default_factory' in ArgTr

Error message

Cannot specify both 'default' and 'default_factory' in ArgTransform. Use either 'default' for a static value or 'default_factory' for a callable.

What it means

ArgTransform validates in __post_init__ that at most one of 'default' (a static value) and 'default_factory' (a callable producing a value) is set. Both encode a default, so specifying both is ambiguous and rejected with ValueError.

Source

Thrown at fastmcp_slim/fastmcp/tools/tool_transform.py:188

        ```
    """

    name: str | NotSetT = NotSet
    description: str | NotSetT = NotSet
    default: Any | NotSetT = NotSet
    default_factory: Callable[[], Any] | NotSetT = NotSet
    type: Any | NotSetT = NotSet
    hide: bool = False
    required: Literal[True] | NotSetT = NotSet
    examples: Any | NotSetT = NotSet

    def __post_init__(self):
        """Validate that only one of default or default_factory is provided."""
        has_default = self.default is not NotSet
        has_factory = self.default_factory is not NotSet

        if has_default and has_factory:
            raise ValueError(
                "Cannot specify both 'default' and 'default_factory' in ArgTransform. "
                "Use either 'default' for a static value or 'default_factory' for a callable."
            )

        if has_factory and not self.hide:
            raise ValueError(
                "default_factory can only be used with hide=True. "
                "Visible parameters must use static 'default' values since JSON schema "
                "cannot represent dynamic factories."
            )

        if self.required is True and (has_default or has_factory):
            raise ValueError(
                "Cannot specify 'required=True' with 'default' or 'default_factory'. "
                "Required parameters cannot have defaults."
            )

        if self.hide and self.required is True:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Keep only one: remove default= if you need a dynamically computed default (default_factory).
  2. Or remove default_factory= if the default is a static value and keep default=.
  3. If the value came from config, ensure only one of the two keys is present before constructing ArgTransform.

Example fix

// before
ArgTransform(default=5, default_factory=lambda: compute())

// after
ArgTransform(default_factory=lambda: compute())
Defensive patterns

Strategy: validation

Validate before calling

def check_arg_transform(t: ArgTransform) -> None:
    if t.default is not NotSet and t.default_factory is not NotSet:
        raise ValueError("Specify only one of default or default_factory")

Try / catch

try:
    t = ArgTransform(default=1, default_factory=int)
except ValueError as e:
    log.warning("Bad ArgTransform: %s", e)
    t = ArgTransform(default=1)  # fallback to static default

Prevention

When it happens

Trigger: Constructing ArgTransform(default=..., default_factory=..., ...) with both fields non-NotSet, e.g. when converting ArgTransformConfig dicts or copy-pasting transform definitions.

Common situations: Migrating an existing ArgTransform to use default_factory but forgetting to remove default=; building transforms programmatically and merging two config dicts.

Related errors


AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29). Data as JSON: /api/errors/65358224f299995c. Report an issue: GitHub.