ComposioHQ/composio · error · JSONSchemaRefResolutionError
Cannot resolve $ref {pointer}
Error message
Cannot resolve $ref {pointer} What it means
A JSON Schema $ref pointer (e.g. #/$defs/Foo) could not be resolved while dereference_json_schema was inlining the schema. The pointer's target is missing from the document or the JSON pointer is malformed. This fires in strict (default 'throw') mode; the SDK treats a dangling internal $ref as a bug in the schema producer.
Source
Thrown at python/composio/utils/json_schema.py:120
elif isinstance(cursor, dict):
if segment not in cursor:
return _Resolution(ok=False, reason="missing-target", failed_at=segment)
cursor = cursor[segment]
else:
return _Resolution(ok=False, reason="missing-target", failed_at=segment)
return _Resolution(ok=True, value=cursor)
def _raise_resolution_error(pointer: str, resolution: _Resolution) -> t.NoReturn:
if resolution.reason == "malformed-pointer":
raise JSONSchemaRefResolutionError(
f"Unsupported $ref pointer: {pointer}",
meta={"ref": pointer},
)
meta: t.Dict[str, t.Any] = {"ref": pointer}
if resolution.failed_at is not None:
meta["failed_at"] = resolution.failed_at
raise JSONSchemaRefResolutionError(
f"Cannot resolve $ref {pointer}",
meta=meta,
)
def dereference_json_schema(
schema: t.Any,
*,
on_unresolved: UnresolvedRefStrategy = "throw",
on_replace: t.Optional[OnReplace] = None,
) -> t.Any:
"""Inline internal ``$ref`` pointers (``#/$defs/...`` and legacy
``#/definitions/...``), returning a new schema; the input is never mutated.
External refs (``http://``, ``https://``, …) are left untouched (and logged
once for audit, since a downstream resolver fetching them could enable SSRF
or local-file disclosure). Cycles — both ``$ref`` cycles and JS-object-style
identity cycles — are broken with a permissive ``{"type": "object",View on GitHub (pinned to 64b1b85502)
Solutions
- Fix the schema so every $ref target exists under $defs/definitions
- If the schema comes from an upstream service you cannot edit, call dereference_json_schema with on_unresolved='sentinel' to replace danglers with a permissive object
- Upgrade composio — newer versions default to sentinel degradation for API-sourced schemas
- If you own the schema, validate it with a JSON Schema library (jsonschema.check_schema) before passing it in
Example fix
# before out = dereference_json_schema(schema) # after out = dereference_json_schema(schema, on_unresolved="sentinel")
Defensive patterns
Strategy: try-catch
Validate before calling
def has_dangling_refs(schema):
import json
defs = {**schema.get('$defs', {}), **schema.get('definitions', {})}
text = json.dumps(schema)
import re
for m in re.finditer(r'"\$ref"\s*:\s*"#/\$defs/([^"]+)"', text):
if m.group(1) not in defs:
return True
return False Type guard
def is_resolvable_schema(s: dict) -> bool:
defs = {**s.get('$defs', {}), **s.get('definitions', {})}
def walk(n):
if isinstance(n, dict):
r = n.get('$ref')
if isinstance(r, str) and r.startswith('#/$defs/'):
if r.split('/')[-1] not in defs: return False
return all(walk(v) for v in n.values())
if isinstance(n, list):
return all(walk(v) for v in n)
return True
return walk(s) Try / catch
from composio.exceptions import JSONSchemaRefResolutionError
try:
out = dereference_json_schema(schema, on_unresolved="sentinel")
except JSONSchemaRefResolutionError as e:
logger.warning("unresolvable $ref: %s", e.meta)
out = schema # use raw schema with refs Prevention
- Prefer on_unresolved='sentinel' for schemas you don't control
- Run a JSON Schema linter over generated schemas in CI
When it happens
Trigger: Calling dereference_json_schema (or APIs that use it: process_file_uploadable_schema, substitute_file_uploads, alias_tool_input_schema) on a schema whose $ref points at a #/$defs/... key that does not exist, or uses an escaped/malformed JSON pointer (~ escapes wrong, empty segments).
Common situations: The Composio API ships some output_parameters with a $ref into #/$defs but no $defs block (issue #3307); hand-written custom tool schemas with typos in $defs names; schemas truncated in transit.
Related errors
- JSON Schema node depth exceeded cap ({MAX_NODE_DEPTH})
- JSON Schema $ref chain exceeded depth cap ({MAX_REF_CHAIN_DE
- JSON Schema nesting too deep to dereference
- Invalid property type {p_type}: {schema!r}
- Dynamic-key schema reference {reference!r} must be a local J
AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28).
Data as JSON: /api/errors/e77be0f3c9f44b6f.
Report an issue: GitHub.