PrefectHQ/fastmcp · error

default_factory can only be used with hide=True. Visible par

Error message

default_factory can only be used with hide=True. Visible parameters must use static 'default' values since JSON schema cannot represent dynamic factories.

What it means

ArgTransform requires default_factory to be paired with hide=True. A visible parameter would need its default expressed in the JSON schema sent to clients, but a callable default cannot be serialized to a schema, so the library rejects the combination with ValueError.

Source

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

    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:
            raise ValueError(
                "Cannot specify both 'hide=True' and 'required=True'. "
                "Hidden parameters cannot be required since clients cannot provide them."
            )

        if self.required is False:

View on GitHub (pinned to 1f02114297)

Solutions

  1. Add hide=True if the parameter should not appear in the transformed schema.
  2. Replace default_factory with a static default= if the parameter must remain visible.
  3. Have the replacement function compute the value itself (via forward_raw / parent call) and drop default_factory.

Example fix

// before
ArgTransform(name="api_key", default_factory=lambda: make_key())

// after
ArgTransform(name="api_key", default_factory=lambda: make_key(), hide=True)
Defensive patterns

Strategy: validation

Validate before calling

def check_factory_hidden(t: ArgTransform) -> None:
    if t.default_factory is not NotSet and not t.hide:
        raise ValueError("default_factory requires hide=True")

Try / catch

try:
    t = ArgTransform(default_factory=make)
except ValueError:
    t = ArgTransform(default_factory=make, hide=True)

Prevention

When it happens

Trigger: ArgTransform(default_factory=some_callable) without hide=True (hide defaults to False).

Common situations: Wanting a per-call generated default (timestamp, uuid, token) while still exposing the parameter in the transformed schema; misunderstanding that factories only work for hidden params.

Related errors


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