openai/openai-python · error · ValueError

Unexpected $ref format {ref!r}; Does not start with #/

Error message

Unexpected $ref format {ref!r}; Does not start with #/

What it means

resolve_ref only supports local JSON Schema references of the form '#/...'. A $ref that is an external URL or anchor (e.g. 'http://...', '#name') is rejected because strict-mode schema inlining cannot resolve it.

Source

Thrown at src/openai/lib/_pydantic.py:120

        assert isinstance(ref, str), f"Received non-string $ref - {ref}"

        resolved = resolve_ref(root=root, ref=ref)
        if not is_dict(resolved):
            raise ValueError(f"Expected `$ref: {ref}` to resolved to a dictionary but got {resolved}")

        # properties from the json schema take priority over the ones on the `$ref`
        json_schema.update({**resolved, **json_schema})
        json_schema.pop("$ref")
        # Since the schema expanded from `$ref` might not have `additionalProperties: false` applied,
        # we call `_ensure_strict_json_schema` again to fix the inlined schema and ensure it's valid.
        return _ensure_strict_json_schema(json_schema, path=path, root=root)

    return json_schema


def resolve_ref(*, root: dict[str, object], ref: str) -> object:
    if not ref.startswith("#/"):
        raise ValueError(f"Unexpected $ref format {ref!r}; Does not start with #/")

    path = ref[2:].split("/")
    resolved = root
    for key in path:
        value = resolved[key]
        assert is_dict(value), f"encountered non-dictionary entry while resolving {ref} - {resolved}"
        resolved = value

    return resolved


def is_basemodel_type(typ: type) -> TypeGuard[type[pydantic.BaseModel]]:
    if not inspect.isclass(typ):
        return False
    return issubclass(typ, pydantic.BaseModel)


def is_dataclass_like_type(typ: type) -> bool:

View on GitHub (pinned to 9917c6e28e)

Solutions

  1. Remove or inline the external-referencing types into your own models
  2. Ensure all referenced types are local pydantic v2 models so refs stay '#/$defs/...'
  3. If hand-building a schema, replace remote refs with inlined definitions

Example fix

# before
class Output(BaseModel):
    x: ExternalLibType  # emits external $ref
# after
class LocalType(BaseModel):
    ...  # copy fields locally
class Output(BaseModel):
    x: LocalType
Defensive patterns

Strategy: validation

Validate before calling

schema = Output.model_json_schema()
import json
text = json.dumps(schema)
import re
ext = re.findall(r'"\$ref"\s*:\s*"(?!#/)', text)
assert not ext, f"external refs detected: {ext}"

Prevention

When it happens

Trigger: A pydantic model (or custom schema) that emits external $refs, e.g. referencing types from another library that set external $id/$schema URLs.

Common situations: Models importing types from packages that declare external JSON schema ids; hand-written schemas with remote refs; pydantic v1 generating absolute-ref schemas from certain configurations.

Related errors


AI-assisted analysis of openai/openai-python@9917c6e28e (2026-08-28). Data as JSON: /api/errors/e20b5beaacd36beb. Report an issue: GitHub.