{"record":{"id":"3cc4285a5bf4860e","repo":"rohitg00/ai-engineering-from-scratch","slug":"schema-name-must-be-a-non-negative-integer","errorCode":null,"errorMessage":"schema {name} must be a non-negative integer","messagePattern":"schema (.+?) must be a non-negative integer","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py","lineNumber":104,"sourceCode":"        \"null\": lambda item: item is None,\n        \"boolean\": lambda item: isinstance(item, bool),\n        \"integer\": lambda item: isinstance(item, int) and not isinstance(item, bool),\n        \"number\": lambda item: isinstance(item, (int, float)) and not isinstance(item, bool),\n        \"string\": lambda item: isinstance(item, str),\n        \"array\": lambda item: isinstance(item, list),\n        \"object\": lambda item: isinstance(item, dict),\n    }\n    if expected not in checks:\n        raise ValueError(f\"unsupported schema type: {expected}\")\n    return checks[expected](value)\n\n\ndef _integer_bound(schema: dict[str, Any], name: str) -> int | None:\n    if name not in schema:\n        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\"]","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/rohitg00/ai-engineering-from-scratch/blob/39ea8a1c6d0b61f071226eff7ede4d4105fed820/certifications/claude/lessons/10-tool-use-and-agentic-loops/code/main.py#L86-L122","documentation":"_integer_bound raises ValueError(f'schema {name} must be a non-negative integer') when a numeric constraint keyword (minimum or maximum) is present but its value is not an int, is a bool, or is negative. The function reads bounds for numeric comparisons; a malformed bound cannot be compared safely, so it fails fast. This is about the schema author's constraint value, not the data being validated.","triggerScenarios":"A schema like {\"type\": \"integer\", \"minimum\": \"1\"} (string bound), {\"minimum\": true} (bool), {\"minimum\": -1} (negative), or {\"maximum\": 2.5} (float). Reached whenever _validate_schema_value processes a numeric value and iterates the ('minimum', 'maximum') keyword table.","commonSituations":"Env-var or YAML config flowing into schema bounds as strings; JSON configs where 1.0 parses as float; placeholder values like \"TODO\" left in schemas; booleans leaking in from checkbox-driven schema builders.","solutions":["Make the bound a plain non-negative int literal: {\"minimum\": 1, \"maximum\": 5}.","Coerce config-sourced bounds with int() (and range-check) before building the schema.","Add a schema-lint step that verifies minimum/maximum are non-negative ints at startup.","If fractional bounds are genuinely needed, note this validator subset only supports integer bounds and adjust the design."],"exampleFix":"# before\n{\"type\": \"integer\", \"minimum\": \"1\"}\n# ValueError: schema minimum must be a non-negative integer\n\n# after\n{\"type\": \"integer\", \"minimum\": 1}","handlingStrategy":"validation","validationCode":"def bounds_ok(schema: dict) -> bool:\n    return all(\n        isinstance(schema.get(k, 0), int) and not isinstance(schema.get(k, 0), bool) and schema.get(k, 0) >= 0\n        for k in (\"minimum\", \"maximum\")\n    )","typeGuard":"def is_non_negative_int(value) -> bool:\n    return isinstance(value, int) and not isinstance(value, bool) and value >= 0","tryCatchPattern":"try:\n    validate_tool_input(value, schema)\nexcept ValueError as exc:\n    if \"must be a non-negative integer\" in str(exc):\n        schema = normalize_bounds(schema)  # coerce \"1\"->1, 1.0->1 at config load\n        validate_tool_input(value, schema)\n    else:\n        raise","preventionTips":["Coerce config/YAML/env-sourced bounds with int() before building schemas.","Never use booleans or floats for minimum/maximum in this validator.","Assert 0 <= minimum <= maximum at schema build time."],"tags":["python","json-schema","validation","configuration"],"backgroundTag":"invalid-schema-constraint","analyzedSha":"39ea8a1c6d0b61f071226eff7ede4d4105fed820","analyzedAt":"2026-08-26T03:13:46.626Z","schemaVersion":2},"datasetVersion":"2026-08-26T07:17:17.940Z"}