{"record":{"id":"5e7040f0b576ab14","repo":"rohitg00/ai-engineering-from-scratch","slug":"invalid-type-for-location-expected-expected","errorCode":null,"errorMessage":"invalid type for {location}: expected {expected}","messagePattern":"invalid type for (.+?): expected (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py","lineNumber":119,"sourceCode":"        return None\n    value = schema[name]\n    if not isinstance(value, int) or isinstance(value, bool) or value < 0:\n        raise ValueError(f\"schema {name} must be a non-negative integer\")\n    return value\n\n\ndef _validate_schema_value(value: Any, schema: Any, location: str) -> None:\n    if not isinstance(schema, dict):\n        raise ValueError(f\"schema for {location} must be an object\")\n\n    declared_type = schema.get(\"type\")\n    if declared_type is not None:\n        declared_types = declared_type if isinstance(declared_type, list) else [declared_type]\n        if not declared_types or not all(isinstance(item, str) for item in declared_types):\n            raise ValueError(f\"schema type for {location} must be a string or non-empty string list\")\n        if not any(_matches_json_type(value, item) for item in declared_types):\n            expected = \" or \".join(declared_types)\n            raise ValueError(f\"invalid type for {location}: expected {expected}\")\n\n    if \"enum\" in schema:\n        choices = schema[\"enum\"]\n        if not isinstance(choices, list) or not choices:\n            raise ValueError(f\"schema enum for {location} must be a non-empty list\")\n        if value not in choices:\n            raise ValueError(f\"invalid value for {location}: not in enum\")\n\n    if isinstance(value, (int, float)) and not isinstance(value, bool):\n        for keyword, comparison, message in (\n            (\"minimum\", lambda current, bound: current >= bound, \"below minimum\"),\n            (\"maximum\", lambda current, bound: current <= bound, \"above maximum\"),\n            (\"exclusiveMinimum\", lambda current, bound: current > bound, \"at or below exclusive minimum\"),\n            (\"exclusiveMaximum\", lambda current, bound: current < bound, \"at or above exclusive maximum\"),\n        ):\n            if keyword not in schema:\n                continue\n            bound = schema[keyword]","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py#L101-L137","documentation":"_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.","triggerScenarios":"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().","commonSituations":"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.","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)."],"exampleFix":"# before\nvalidate_tool_input({\"count\": \"3\"}, {\"type\": \"object\", \"properties\": {\"count\": {\"type\": \"integer\"}}})\n# ValueError: invalid type for $.count: expected integer\n\n# after\nvalidate_tool_input({\"count\": 3}, ...)","handlingStrategy":"retry","validationCode":"def coerce_to_declared(value, schema):\n    t = schema.get(\"type\")\n    if t == \"integer\" and isinstance(value, str) and value.isdigit():\n        return int(value)\n    if t == \"number\" and isinstance(value, str):\n        try:\n            return float(value)\n        except ValueError:\n            return value\n    return value","typeGuard":"def matches_declared(value, expected: str) -> bool:\n    checks = {\n        \"boolean\": lambda v: isinstance(v, bool),\n        \"integer\": lambda v: isinstance(v, int) and not isinstance(v, bool),\n        \"number\": lambda v: isinstance(v, (int, float)) and not isinstance(v, bool),\n        \"string\": lambda v: isinstance(v, str),\n        \"array\": lambda v: isinstance(v, list),\n        \"object\": lambda v: isinstance(v, dict),\n    }\n    return expected not in checks or checks[expected](value)","tryCatchPattern":"for attempt in range(max_attempts):\n    try:\n        return validate_tool_input(model_output, schema)\n    except ValueError as exc:\n        if not str(exc).startswith(\"invalid type for\"):\n            raise\n        model_output = generate(f\"Previous output failed: {exc}. Return correct JSON types.\")\nraise ContractViolation(last_error)","preventionTips":["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."],"tags":["python","json-schema","type-mismatch","validation"],"backgroundTag":"json-schema-type-mismatch","analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}