PrefectHQ/fastmcp · error · ValueError

Dict response_type cannot be empty.

Error message

Dict response_type cannot be empty.

What it means

FastMCP supports a dict shorthand for ctx.elicit() response_type to build a single-select titled enum (e.g. {"low": {"title": "Low"}}). Passing an empty dict gives the parser nothing to build an enum schema from, so it raises immediately rather than emitting a degenerate schema to the client.

Source

Thrown at fastmcp_slim/fastmcp/server/elicitation.py:230

    if title is not None:
        value_schema["title"] = title
    if description is not None:
        value_schema["description"] = description


def _is_scalar_type(response_type: Any) -> bool:
    """Check if response_type is a scalar type that needs wrapping."""
    return (
        response_type in {bool, int, float, str}
        or get_origin(response_type) is Literal
        or (isinstance(response_type, type) and issubclass(response_type, Enum))
    )


def _parse_dict_syntax(d: dict[str, Any]) -> ElicitConfig:
    """Parse dict syntax: {"low": {"title": "..."}} -> single-select titled."""
    if not d:
        raise ValueError("Dict response_type cannot be empty.")
    enum_schema = _dict_to_enum_schema(d, multi_select=False)
    return ElicitConfig(
        schema={
            "type": "object",
            "properties": {"value": enum_schema},
            "required": ["value"],
        },
        response_type=None,
        is_raw=True,
    )


def _parse_list_syntax(lst: list[Any]) -> ElicitConfig:
    """Parse list patterns: [[...]], [{...}], or [...]."""
    # [["a", "b", "c"]] -> multi-select untitled
    if (
        len(lst) == 1
        and isinstance(lst[0], list)

View on GitHub (pinned to 1f02114297)

Solutions

  1. Populate the dict with at least one option before calling ctx.elicit(), e.g. {"low": {"title": "Low"}}
  2. Guard the call: only elicit when the options dict is non-empty, otherwise skip the elicitation or return early
  3. If no options exist, reconsider the flow — eliciting a choice with zero choices is not meaningful

Example fix

// before
await ctx.elicit(response_type={})
// after
choices = {"low": {"title": "Low"}, "high": {"title": "High"}}
if not choices:
    raise ValueError("No choices available")
await ctx.elicit(response_type=choices)
Defensive patterns

Strategy: validation

Validate before calling

def validate_options(options):
    if not isinstance(options, dict) or not options:
        raise ValueError("elicit dict response_type must have at least one option")
    return options

# call before eliciting
validate_options(choices)
await ctx.elicit(response_type=choices)

Type guard

def is_nonempty_str_dict(d: object) -> bool:
    return isinstance(d, dict) and len(d) > 0

Try / catch

try:
    result = await ctx.elicit(response_type=choices)
except ValueError as e:
    if "cannot be empty" in str(e):
        logger.error("elicitation options were empty; skipping prompt")
        return None
    raise

Prevention

When it happens

Trigger: Calling ctx.elicit(response_type={}) or parse_elicit_response_type({}) — a dict response_type with zero keys.

Common situations: Building the options dict dynamically from data (e.g. from a DB or config) that came back empty; a typo like response_type=options where options was never populated.

Related errors


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