rohitg00/ai-engineering-from-scratch · error · ValueError

property names must be strings

Error message

property names must be strings

What it means

Key-type check while recursing over an object schema's properties in validate_schema_shape: a property name inside the properties mapping is not a string. Non-string keys (possible via programmatic construction) are not representable in JSON and would break serialization and argument matching.

Solutions

  1. Use string keys for every property name
  2. Check for int or tuple keys introduced by programmatic schema builders
  3. Str-coerce keys when deriving schemas from dataclasses or dicts
  4. Assert all keys are strings when generating schemas in tests
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at phases/19-capstone-projects/21-tool-registry-schema-validation/code/main.py:143 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/f3c0be2edb3d9044. Report an issue: GitHub.

Appendix: source

Thrown at phases/19-capstone-projects/21-tool-registry-schema-validation/code/main.py:143

    if min_len is not None:
        if isinstance(min_len, bool) or not isinstance(min_len, int) or min_len < 0:
            raise ValueError("minLength must be a non-negative integer")
    max_len = schema.get("maxLength")
    if max_len is not None:
        if isinstance(max_len, bool) or not isinstance(max_len, int) or max_len < 0:
            raise ValueError("maxLength must be a non-negative integer")
    if min_len is not None and max_len is not None and min_len > max_len:
        raise ValueError("minLength cannot be greater than maxLength")
    pattern = schema.get("pattern")
    if pattern is not None and not isinstance(pattern, str):
        raise ValueError("pattern must be a string")
    props = schema.get("properties")
    if props is not None:
        if not isinstance(props, dict):
            raise ValueError("properties must be a dict")
        for pname, psub in props.items():
            if not isinstance(pname, str):
                raise ValueError("property names must be strings")
            validate_schema_shape(psub)
    items = schema.get("items")
    if items is not None:
        validate_schema_shape(items)
    req = schema.get("required")
    if req is not None:
        if not isinstance(req, list) or not all(isinstance(x, str) for x in req):
            raise ValueError("required must be list[str]")


def _path(prefix: str, segment: str | int) -> str:
    seg = str(segment).replace("~", "~0").replace("/", "~1")
    return f"{prefix}/{seg}"


def _type_matches(value: Any, expected: str) -> bool:
    types = PRIMITIVE_TYPE_MAP[expected]
    if expected == "boolean":

View on GitHub (pinned to 39ea8a1c6d)