ComposioHQ/composio · error · ValueError

Unresolvable dynamic-key schema reference: {reference!r}

Error message

Unresolvable dynamic-key schema reference: {reference!r}

What it means

The $ref is a well-formed local JSON Pointer ("#/...") but the pointer path does not exist in the root schema: a token doesn't match a key, or a list index is invalid/out of range. _resolve_local_json_pointer walks the tokens (applying ~0/~1 unescaping) and raises this ValueError when traversal dead-ends.

Source

Thrown at python/composio/utils/schema_converter.py:360

        return root_schema
    if not reference.startswith("#/"):
        raise ValueError(
            f"Dynamic-key schema reference {reference!r} must be a local JSON Pointer"
        )

    current: t.Any = root_schema
    for raw_token in unquote(reference[2:]).split("/"):
        token = raw_token.replace("~1", "/").replace("~0", "~")
        if isinstance(current, dict) and token in current:
            current = current[token]
            continue
        if isinstance(current, list):
            try:
                current = current[int(token)]
                continue
            except (ValueError, IndexError):
                pass
        raise ValueError(f"Unresolvable dynamic-key schema reference: {reference!r}")
    return current


def _resolve_default_metadata_schema(
    schema: t.Any,
    root_schema: t.Dict[str, t.Any],
    visited_refs: t.Optional[t.Set[str]] = None,
) -> t.Any:
    """Resolve a schema node without traversing instance-valued annotations."""
    if not isinstance(schema, dict):
        return schema
    reference = schema.get("$ref")
    if not isinstance(reference, str) or not reference.startswith("#/"):
        return schema
    if visited_refs is None:
        visited_refs = set()
    if reference in visited_refs:
        return {key: value for key, value in schema.items() if key != "$ref"}

View on GitHub (pinned to 64b1b85502)

Solutions

  1. Verify the exact token path against the root schema (check spelling/case of every key under definitions/$defs)
  2. Re-fetch or regenerate the schema pair so refs and definitions come from the same source
  3. If the target was renamed, update the $ref to the new location

Example fix

# before
{"$ref": "#/definitions/Usr"}
# after
{"$ref": "#/definitions/User"}
Defensive patterns

Strategy: validation

Validate before calling

from jsonschema import RefResolver  # or manual pointer walk
def pointer_resolves(ref, root):
    if ref == "#": return True
    if not ref.startswith("#/"): return False
    cur = root
    for tok in ref[2:].split("/"):
        tok = tok.replace("~1", "/").replace("~0", "~")
        if isinstance(cur, dict) and tok in cur: cur = cur[tok]
        elif isinstance(cur, list) and tok.isdigit() and int(tok) < len(cur): cur = cur[int(tok)]
        else: return False
    return True

Try / catch

try:
    build_model(schema)
except ValueError as e:
    if "Unresolvable" in str(e):
        raise ToolSchemaError(f"stale ref in {tool.name}: {e}") from e

Prevention

When it happens

Trigger: "$ref": "#/definitions/MissingName" when definitions lacks that key; pointing into an array element that doesn't exist ("#/items/5"); typos in the pointer path; refs valid against a different root document than the one passed in.

Common situations: Renamed or removed definitions in a regenerated schema while stale refs remain; schemas copy-pasted between documents where the target was left behind; case mismatches in definition names; version skew between cached and refreshed tool schemas.

Related errors


AI-assisted analysis of ComposioHQ/composio@64b1b85502 (2026-08-28). Data as JSON: /api/errors/ecdf668a49a1ae12. Report an issue: GitHub.