{"record":{"id":"0031c71b38ef38ca","repo":"PrefectHQ/fastmcp","slug":"elicitation-schema-field-prop-name-contains-a","errorCode":null,"errorMessage":"Elicitation schema field '{prop_name}' contains a reference '{ref_path}' that could not be validated. Only references to enum types or primitive types are allowed.","messagePattern":"Elicitation schema field '(.+?)' contains a reference '(.+?)' that could not be validated\\. Only references to enum types or primitive types are allowed\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"fastmcp_slim/fastmcp/server/elicitation.py","lineNumber":457,"sourceCode":"        if \"enum\" in prop_schema:\n            continue  # enum fields are allowed regardless of type\n\n        # Handle references to definitions (like Enum types)\n        if \"$ref\" in prop_schema:\n            # Get the referenced definition\n            ref_path = prop_schema[\"$ref\"]\n            if ref_path.startswith(\"#/$defs/\"):\n                def_name = ref_path[8:]  # Remove \"#/$defs/\" prefix\n                ref_def = schema.get(\"$defs\", {}).get(def_name, {})\n                # If the referenced definition has an enum, it's allowed\n                if \"enum\" in ref_def:\n                    continue\n                # If the referenced definition has a type that's allowed, it's allowed\n                ref_type = ref_def.get(\"type\")\n                if ref_type in ALLOWED_TYPES:\n                    continue\n            # If we can't determine what the ref points to, reject it for safety\n            raise TypeError(\n                f\"Elicitation schema field '{prop_name}' contains a reference '{ref_path}' \"\n                \"that could not be validated. Only references to enum types or primitive types are allowed.\"\n            )\n\n        # Handle union types (oneOf/anyOf)\n        if \"oneOf\" in prop_schema or \"anyOf\" in prop_schema:\n            union_schemas = prop_schema.get(\"oneOf\", []) + prop_schema.get(\"anyOf\", [])\n            for union_schema in union_schemas:\n                # Allow const and enum in unions\n                if \"const\" in union_schema or \"enum\" in union_schema:\n                    continue\n                union_type = union_schema.get(\"type\")\n                if union_type not in ALLOWED_TYPES:\n                    raise TypeError(\n                        f\"Elicitation schema field '{prop_name}' has union type '{union_type}' which is not \"\n                        f\"a primitive type. Only {ALLOWED_TYPES} are allowed in elicitation schemas.\"\n                    )\n            continue","sourceCodeStart":439,"sourceCodeEnd":475,"githubUrl":"https://github.com/PrefectHQ/fastmcp/blob/1f021142978e0861cd910c8df4e8074bc7cf3978/fastmcp_slim/fastmcp/server/elicitation.py#L439-L475","documentation":"Elicitation schemas may contain $ref pointers only when they resolve to enum or primitive-typed definitions. If a property's $ref cannot be resolved (missing $defs entry, ref to a nested object/array, or a ref the validator can't trace), the validator rejects it defensively rather than sending an unverifiable schema to the client.","triggerScenarios":"A property schema like {\"$ref\": \"#/$defs/Foo\"} where $defs lacks Foo, or where the resolved definition has no 'type' and no enum/const, during get_elicitation_schema validation.","commonSituations":"Manually composing schemas with shared $defs; post-processing/compressing Pydantic schemas so refs dangle; referencing a BaseModel (object) instead of an Enum; schema tooling rewriting ref paths.","solutions":["Ensure every $ref resolves to a $defs entry with an allowed primitive type or an enum definition","Inline the enum/primitive directly in the property instead of using $ref","Use FastMCP's schema generation (Pydantic models / shorthand forms) rather than hand-built $defs — its generator inlines enums automatically","Run compress_schema or equivalent before validation if composing schemas programmatically"],"exampleFix":"// before\n{\"properties\": {\"color\": {\"$ref\": \"#/$defs/Missing\"}}}\n// after\n{\"properties\": {\"color\": {\"type\": \"string\", \"enum\": [\"red\", \"blue\"]}}}","handlingStrategy":"validation","validationCode":"def check_refs(schema: dict) -> None:\n    defs = schema.get(\"$defs\", {})\n    for prop in schema.get(\"properties\", {}).values():\n        ref = prop.get(\"$ref\")\n        if not ref:\n            continue\n        name = ref.rsplit(\"/\", 1)[-1]\n        target = defs.get(name, {})\n        if target.get(\"type\") not in {\"string\", \"number\", \"integer\", \"boolean\"} and \"enum\" not in target:\n            raise TypeError(f\"ref {ref} must resolve to a primitive or enum definition\")","typeGuard":"def ref_is_resolvable_primitive(schema: dict, ref_path: str) -> bool:\n    if not ref_path.startswith(\"#/$defs/\"):\n        return False\n    target = schema.get(\"$defs\", {}).get(ref_path.rsplit(\"/\", 1)[-1], {})\n    return target.get(\"type\") in {\"string\", \"number\", \"integer\", \"boolean\"} or \"enum\" in target","tryCatchPattern":"try:\n    schema = get_elicitation_schema(response_type)\nexcept TypeError as e:\n    if \"could not be validated\" in str(e) and \"$ref\" in str(e) or \"reference\" in str(e):\n        logger.error(\"inline your enum/primitive instead of using $ref\")\n        return None\n    raise","preventionTips":["Avoid hand-built $defs; let FastMCP's generator inline enums automatically","If composing schemas, resolve and inline all refs before validation","Only reference Enum types or primitive-typed definitions","After schema compression/post-processing, re-validate refs still resolve"],"tags":["elicitation","json-schema","refs","fastmcp"],"backgroundTag":"unresolvable-schema-ref","analyzedSha":"1f021142978e0861cd910c8df4e8074bc7cf3978","analyzedAt":"2026-08-29T14:31:16.082Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}