PrefectHQ/fastmcp · error · ValueError
Elicitation responses must be serializable as a JSON object
Error message
Elicitation responses must be serializable as a JSON object (dict). Received: {result.content!r} What it means
MCP elicitation responses must be a JSON-serializable dict (object). When an elicitation handler returns a bare scalar (str/int/float/bool) for a schema that is not the special single-`value`-property form case, FastMCP raises this ValueError because it cannot wrap the content into an MCP ElicitResult. The repr of the offending content is included.
Source
Thrown at fastmcp_slim/fastmcp/client/elicitation.py:78
params.message,
response_type,
params,
context, # ty: ignore[invalid-argument-type]
)
# if the user returns data, we assume they've accepted the elicitation
if not isinstance(result, ElicitResult):
result = ElicitResult(action="accept", content=result)
content = to_jsonable_python(result.content)
if not isinstance(content, dict | None):
# Auto-wrap scalar values for ScalarElicitationType schemas
# (single "value" property). This lets handlers return T directly
# for ctx.elicit("msg", str/int/float/bool).
if isinstance(params, ElicitRequestFormParams) and set(
params.requested_schema.get("properties", {}).keys()
) == {"value"}:
content = {"value": content}
else:
raise ValueError(
"Elicitation responses must be serializable as a JSON object (dict). Received: "
f"{result.content!r}"
)
return MCPElicitResult(
_meta=result.meta, # type: ignore[call-arg] # _meta is Pydantic alias for meta field
action=result.action,
content=content,
)
except Exception as e:
return mcp_types.ErrorData(
code=mcp_types.INTERNAL_ERROR,
message=str(e),
)
return _elicitation_handler
View on GitHub (pinned to 1f02114297)
Solutions
- Return a dict whose keys match the requested_schema properties, e.g. {"confirm": True}
- If the schema is the single-`value` form case, return the bare scalar and it is auto-wrapped
- Inspect params.requested_schema in the handler to build the correct response shape
Example fix
// before
def handler(message, params):
return "yes" # ValueError
// after
def handler(message, params):
return {"value": "yes"} # or keys matching requested_schema properties Defensive patterns
Strategy: validation
Validate before calling
def valid_elicitation_response(content, params) -> bool:
if isinstance(content, dict):
return True
props = set(params.requested_schema.get("properties", {}).keys())
return props == {"value"} and isinstance(content, (str, int, float, bool)) Type guard
def is_json_object(content: object) -> TypeGuard[dict]:
return isinstance(content, dict) Try / catch
try:
... # handler runs during elicitation
except ValueError as e:
if "serializable as a JSON object" in str(e):
logger.error("elicitation handler must return a dict: %r", e)
raise Prevention
- Always return dicts keyed by requested_schema properties
- Return bare scalars only for single-`value` schemas
- Test elicitation handlers against the actual requested schemas
When it happens
Trigger: An `elicitation_handler` returning e.g. `"yes"` or `42` while the request's requested_schema has properties other than a single `value` property.
Common situations: Handlers written for simple string elicitations reused on structured schemas; returning raw user input without wrapping it in the schema's property names.
Related errors
- CLI state is invalid: {path.name}
- ClientGroup requires at least one client
- Protocol mode for server {name!r} must be a string
- messages[{i}] must be Message, got {type(item).__name__}. Us
- messages must be str or list[Message], got {type(messages)._
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/dfbcac319769aa1a.
Report an issue: GitHub.