PrefectHQ/fastmcp · error · ValueError

Invalid list response_type format. Received: {lst}

Error message

Invalid list response_type format. Received: {lst}

What it means

When response_type is a plain list, FastMCP recognizes only three shapes: [["a","b"]] (multi-select untitled), [{"opt": {"title": ...}}] (multi-select titled), and ["a","b"] (single-select untitled). Any other list — mixed types, non-string items, nested dicts not matching the titled pattern — is rejected with this error.

Source

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

                "required": ["value"],
            },
            response_type=None,
            is_raw=True,
        )

    # ["a", "b", "c"] -> single-select untitled
    if lst and all(isinstance(item, str) for item in lst):
        # Construct Literal type from tuple - use cast since we can't construct Literal dynamically
        # but we know the values are all strings
        choice_literal: type[Any] = cast(type[Any], Literal[tuple(lst)])  # type: ignore[valid-type]  # ty:ignore[invalid-type-form]
        wrapped = ScalarElicitationType[choice_literal]  # type: ignore[valid-type]  # ty:ignore[invalid-type-form]
        return ElicitConfig(
            schema=get_elicitation_schema(wrapped),
            response_type=wrapped,
            is_raw=False,
        )

    raise ValueError(f"Invalid list response_type format. Received: {lst}")


def _parse_generic_list(response_type: Any) -> ElicitConfig:
    """Parse list[X] type annotation -> multi-select."""
    wrapped = ScalarElicitationType[response_type]
    return ElicitConfig(
        schema=get_elicitation_schema(wrapped),
        response_type=wrapped,
        is_raw=False,
    )


def _parse_scalar_type(response_type: Any) -> ElicitConfig:
    """Parse scalar types (bool, int, float, str, Literal, Enum)."""
    wrapped = ScalarElicitationType[response_type]
    return ElicitConfig(
        schema=get_elicitation_schema(wrapped),
        response_type=wrapped,

View on GitHub (pinned to 1f02114297)

Solutions

  1. Use only string options for the plain-list shorthand, e.g. ["red", "green"]
  2. For non-string choices, define an Enum or Literal type and pass that as response_type
  3. For multi-select use the exact nested form [["a","b"]] or [{"opt": {"title": "..."}}]
  4. Ensure the list is non-empty and its elements are homogeneous strings

Example fix

// before
await ctx.elicit(response_type=[1, 2, 3])
// after
from enum import Enum
class Level(Enum):
    ONE = 1
    TWO = 2
await ctx.elicit(response_type=Level)
Defensive patterns

Strategy: validation

Validate before calling

def validate_list_response_type(options):
    if not isinstance(options, list) or not options:
        raise ValueError("must be a non-empty list")
    ok = (
        (len(options) == 1 and isinstance(options[0], list) and options[0]
         and all(isinstance(i, str) for i in options[0]))
        or (len(options) == 1 and isinstance(options[0], dict) and options[0])
        or all(isinstance(i, str) for i in options)
    )
    if not ok:
        raise ValueError(f"unsupported list shape: {options!r}")
    return options

Type guard

def is_valid_list_shorthand(lst: object) -> bool:
    if not isinstance(lst, list) or not lst:
        return False
    if len(lst) == 1 and isinstance(lst[0], list):
        return bool(lst[0]) and all(isinstance(i, str) for i in lst[0])
    if len(lst) == 1 and isinstance(lst[0], dict):
        return bool(lst[0])
    return all(isinstance(i, str) for i in lst)

Try / catch

try:
    result = await ctx.elicit(response_type=options)
except ValueError as e:
    if "Invalid list response_type" in str(e):
        logger.error(f"bad options shape: {options!r}; use ['a','b'], [['a','b']], or [{{'opt': {{'title': ...}}}}]")
        return None
    raise

Prevention

When it happens

Trigger: Passing a list containing non-strings like [1, 2, 3], ["a", 2], [], ["a", {"b": 1}], or a single-element list whose item is neither a non-empty string list nor a non-empty dict.

Common situations: Trying to elicit a numeric choice with [1,2,3]; passing an empty options list; accidentally wrapping options twice; building options from Enum members without converting to strings.

Related errors


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