{"record":{"id":"e77be0f3c9f44b6f","repo":"ComposioHQ/composio","slug":"cannot-resolve-ref-pointer","errorCode":null,"errorMessage":"Cannot resolve $ref {pointer}","messagePattern":"Cannot resolve \\$ref (.+?)","errorType":"exception","errorClass":"JSONSchemaRefResolutionError","httpStatus":null,"severity":"error","filePath":"python/composio/utils/json_schema.py","lineNumber":120,"sourceCode":"        elif isinstance(cursor, dict):\n            if segment not in cursor:\n                return _Resolution(ok=False, reason=\"missing-target\", failed_at=segment)\n            cursor = cursor[segment]\n        else:\n            return _Resolution(ok=False, reason=\"missing-target\", failed_at=segment)\n    return _Resolution(ok=True, value=cursor)\n\n\ndef _raise_resolution_error(pointer: str, resolution: _Resolution) -> t.NoReturn:\n    if resolution.reason == \"malformed-pointer\":\n        raise JSONSchemaRefResolutionError(\n            f\"Unsupported $ref pointer: {pointer}\",\n            meta={\"ref\": pointer},\n        )\n    meta: t.Dict[str, t.Any] = {\"ref\": pointer}\n    if resolution.failed_at is not None:\n        meta[\"failed_at\"] = resolution.failed_at\n    raise JSONSchemaRefResolutionError(\n        f\"Cannot resolve $ref {pointer}\",\n        meta=meta,\n    )\n\n\ndef dereference_json_schema(\n    schema: t.Any,\n    *,\n    on_unresolved: UnresolvedRefStrategy = \"throw\",\n    on_replace: t.Optional[OnReplace] = None,\n) -> t.Any:\n    \"\"\"Inline internal ``$ref`` pointers (``#/$defs/...`` and legacy\n    ``#/definitions/...``), returning a new schema; the input is never mutated.\n\n    External refs (``http://``, ``https://``, …) are left untouched (and logged\n    once for audit, since a downstream resolver fetching them could enable SSRF\n    or local-file disclosure). Cycles — both ``$ref`` cycles and JS-object-style\n    identity cycles — are broken with a permissive ``{\"type\": \"object\",","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/ComposioHQ/composio/blob/64b1b85502b1beeb2379e6c9e8bf1104504fa637/python/composio/utils/json_schema.py#L102-L138","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"# before\nout = dereference_json_schema(schema)\n# after\nout = dereference_json_schema(schema, on_unresolved=\"sentinel\")","handlingStrategy":"try-catch","validationCode":"def has_dangling_refs(schema):\n    import json\n    defs = {**schema.get('$defs', {}), **schema.get('definitions', {})}\n    text = json.dumps(schema)\n    import re\n    for m in re.finditer(r'\"\\$ref\"\\s*:\\s*\"#/\\$defs/([^\"]+)\"', text):\n        if m.group(1) not in defs:\n            return True\n    return False","typeGuard":"def is_resolvable_schema(s: dict) -> bool:\n    defs = {**s.get('$defs', {}), **s.get('definitions', {})}\n    def walk(n):\n        if isinstance(n, dict):\n            r = n.get('$ref')\n            if isinstance(r, str) and r.startswith('#/$defs/'):\n                if r.split('/')[-1] not in defs: return False\n            return all(walk(v) for v in n.values())\n        if isinstance(n, list):\n            return all(walk(v) for v in n)\n        return True\n    return walk(s)","tryCatchPattern":"from composio.exceptions import JSONSchemaRefResolutionError\ntry:\n    out = dereference_json_schema(schema, on_unresolved=\"sentinel\")\nexcept JSONSchemaRefResolutionError as e:\n    logger.warning(\"unresolvable $ref: %s\", e.meta)\n    out = schema  # use raw schema with refs","preventionTips":["Prefer on_unresolved='sentinel' for schemas you don't control","Run a JSON Schema linter over generated schemas in CI"],"tags":["json-schema","ref-resolution","python"],"backgroundTag":"json-schema-ref-resolution-failed","analyzedSha":"64b1b85502b1beeb2379e6c9e8bf1104504fa637","analyzedAt":"2026-08-28T15:39:33.623Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}