rohitg00/ai-engineering-from-scratch · error · ValueError
invalid type for {location}: expected {expected}
Error message
invalid type for {location}: expected {expected} What it means
_validate_schema_value raises ValueError(f'invalid type for {location}: expected {expected}') when the VALUE being validated does not match any of the schema's declared type(s). Unlike the schema-shape errors, this flags bad data: the value at {location} is, say, a string where the schema declares integer, and the message joins all allowed types with ' or '. Booleans are deliberately not accepted as integers or numbers here.
Source
Thrown at certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py:119
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"),
):
if keyword not in schema:
continue
bound = schema[keyword]View on GitHub (pinned to 39ea8a1c6d)
Solutions
- Coerce the value before validating (int('3') -> 3) or fix the producer: prompt the model to emit raw JSON numbers, not quoted ones.
- If multiple types are acceptable, declare a type list: {"type": ["integer", "string"]}.
- Inspect {location} and the expected types in the message to find exactly which field failed.
- In repair loops, feed this precise message back to the model as corrective feedback (the BoundedExtractor pattern).
Example fix
# before
validate_tool_input({"count": "3"}, {"type": "object", "properties": {"count": {"type": "integer"}}})
# ValueError: invalid type for $.count: expected integer
# after
validate_tool_input({"count": 3}, ...) Defensive patterns
Strategy: retry
Validate before calling
def coerce_to_declared(value, schema):
t = schema.get("type")
if t == "integer" and isinstance(value, str) and value.isdigit():
return int(value)
if t == "number" and isinstance(value, str):
try:
return float(value)
except ValueError:
return value
return value Type guard
def matches_declared(value, expected: str) -> bool:
checks = {
"boolean": lambda v: isinstance(v, bool),
"integer": lambda v: isinstance(v, int) and not isinstance(v, bool),
"number": lambda v: isinstance(v, (int, float)) and not isinstance(v, bool),
"string": lambda v: isinstance(v, str),
"array": lambda v: isinstance(v, list),
"object": lambda v: isinstance(v, dict),
}
return expected not in checks or checks[expected](value) Try / catch
for attempt in range(max_attempts):
try:
return validate_tool_input(model_output, schema)
except ValueError as exc:
if not str(exc).startswith("invalid type for"):
raise
model_output = generate(f"Previous output failed: {exc}. Return correct JSON types.")
raise ContractViolation(last_error) Prevention
- Instruct models to emit raw JSON numbers/booleans, never quoted or 0/1 substitutes.
- Coerce stringly-typed inputs (env vars, forms, CLI) before validation.
- Feed the precise location+expected message back as repair feedback in retry loops.
When it happens
Trigger: Validating tool input like {"count": "3"} against {"type": "integer"}; passing true where a number is declared; a wrong-type value at any nested property or array item, reached recursively from validate().
Common situations: Model-produced tool calls with stringified numbers; LLM emitting true/false for 1/0; CLI/env inputs arriving as strings; frontends sending string numbers from form fields.
Related errors
- unsupported schema type: {expected}
- schema {name} must be a non-negative integer
- schema for {location} must be an object
- schema type for {location} must be a string or non-empty str
- schema enum for {location} must be a non-empty list
AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26).
Data as JSON: /api/errors/5e7040f0b576ab14.
Report an issue: GitHub.