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

schema type for {location} must be a string or non-empty str

Error message

schema type for {location} must be a string or non-empty string list

What it means

_validate_schema_value raises ValueError(f'schema type for {location} must be a string or non-empty string list') when the 'type' keyword of a (sub)schema is neither a string nor a non-empty list of strings - e.g. an int, bool, None, empty list, or a list containing non-strings. The validator supports scalar types and type arrays and rejects anything else as an authoring error in the schema itself.

Source

Thrown at certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py:116

def _integer_bound(schema: dict[str, Any], name: str) -> int | None:
    if name not in schema:
        return None
    value = schema[name]
    if not isinstance(value, int) or isinstance(value, bool) or value < 0:
        raise ValueError(f"schema {name} must be a non-negative integer")
    return value


def _validate_schema_value(value: Any, schema: Any, location: str) -> None:
    if not isinstance(schema, dict):
        raise ValueError(f"schema for {location} must be an object")

    declared_type = schema.get("type")
    if declared_type is not None:
        declared_types = declared_type if isinstance(declared_type, list) else [declared_type]
        if not declared_types or not all(isinstance(item, str) for item in declared_types):
            raise ValueError(f"schema type for {location} must be a string or non-empty string list")
        if not any(_matches_json_type(value, item) for item in declared_types):
            expected = " or ".join(declared_types)
            raise ValueError(f"invalid type for {location}: expected {expected}")

    if "enum" in schema:
        choices = schema["enum"]
        if not isinstance(choices, list) or not choices:
            raise ValueError(f"schema enum for {location} must be a non-empty list")
        if value not in choices:
            raise ValueError(f"invalid value for {location}: not in enum")

    if isinstance(value, (int, float)) and not isinstance(value, bool):
        for keyword, comparison, message in (
            ("minimum", lambda current, bound: current >= bound, "below minimum"),
            ("maximum", lambda current, bound: current <= bound, "above maximum"),
            ("exclusiveMinimum", lambda current, bound: current > bound, "at or below exclusive minimum"),
            ("exclusiveMaximum", lambda current, bound: current < bound, "at or above exclusive maximum"),
        ):

View on GitHub (pinned to 39ea8a1c6d)

Solutions

  1. Set 'type' to a single supported string or a non-empty list of supported strings.
  2. Read the {location} in the message to find which subschema has the bad type keyword.
  3. Lint generated schemas: assert type fields are str or a non-empty list[str] before use.
  4. When templating schemas, omit the type key rather than writing null.

Example fix

# before
{"type": []}
# ValueError: schema type for $.x must be a string or non-empty string list

# after
{"type": ["string", "integer"]}
Defensive patterns

Strategy: type-guard

Validate before calling

def type_keyword_ok(schema: dict) -> bool:
    t = schema.get("type")
    if t is None:
        return True
    if isinstance(t, str):
        return True
    return isinstance(t, list) and len(t) > 0 and all(isinstance(x, str) for x in t)

Type guard

def is_valid_type_keyword(t) -> bool:
    if isinstance(t, str):
        return True
    return isinstance(t, list) and bool(t) and all(isinstance(x, str) for x in t)

Try / catch

try:
    validate_tool_input(value, schema)
except ValueError as exc:
    if "string or non-empty string list" in str(exc):
        raise SchemaError(f"fix the schema: {exc}") from exc
    raise

Prevention

When it happens

Trigger: Schemas such as {"type": 1}, {"type": null}, {"type": []}, {"type": ["string", 2]}, or lists containing unsupported entries. Triggered at the root schema and recursively at any properties/items location named in the message.

Common situations: Programmatic schema builders inserting computed types that yield None; YAML configs where 'type' is parsed as a non-string; partial refactors from scalar types to type lists leaving empty arrays.

Related errors


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