Component
Python SDK, infrahubctl
Infrahub SDK version
1.20.0
Current Behavior
infrahubctl schema load calls infrahub_sdk.ctl.schema.display_schema_load_errors to render server-rejected schema validation errors. The function indexes loc_path[2] and loc_path[4] and casts both to int, assuming the loc tuple shape is ("body", "schemas", <schema_index>, "nodes"|"generics", <node_index>, ...).
When the rejected error originates inside an extensions: block (per docs.infrahub.app/topics/schema-extensions), the loc tuple has an extra segment:
("body", "schemas", <schema_index>, "extensions", "nodes"|"generics"|"relationships", <node_index>, <field>)
So loc_path[4] is a string like "generics" instead of the integer node index. int("generics") raises:
ValueError: invalid literal for int() with base 10: 'generics'
The traceback replaces the intended human-readable error message — the user never sees what the server actually rejected.
Expected Behavior
The server's rejection should be rendered in the same human-readable format as non-extensions errors, e.g.:
Unable to load the schema:
Node: DcimGenericDevice (extensions/generics) | Extra inputs are not permitted (extra_forbidden) — field 'include_in_menu' is not part of the extension schema
Steps to Reproduce
Environment
- Infrahub server: 1.9.2 (any 1.5+ exhibits the rejection that triggers the formatter)
infrahub-sdk[all] 1.20.0
- Python 3.12
Steps
1. Have a running Infrahub instance with a schema that includes a generic that has include_in_menu: true (e.g., the DcimGenericDevice from opsmill/schema-library's base/dcim.yml). Any kind whose existing schema metadata you want to override works.
2. Author a schema-extension YAML that attempts to override a metadata field on an existing kind:
# repro_extension.yml
---
version: "1.0"
extensions:
generics:
- kind: DcimGenericDevice
include_in_menu: false
3. Run infrahubctl schema load:
infrahubctl schema load repro_extension.yml
Actual output (1.20.0)
Schema loading.....
Unable to load the schema:
Traceback (most recent call last):
File ".../site-packages/infrahub_sdk/ctl/schema.py", line 87, in load
display_schema_load_errors(response=response.errors, schemas_data=schemas_data)
File ".../site-packages/infrahub_sdk/ctl/schema.py", line 68, in display_schema_load_errors
node_index = int(loc_path[4])
^^^^^^^^^^^^^^^^
ValueError: invalid literal for int() with base 10: 'generics'
The user sees no human-readable explanation of why the schema was rejected.
Additional Information
Affected code
infrahub_sdk/ctl/schema.py lines 53–103 (in 1.20.0), function display_schema_load_errors:
def display_schema_load_errors(response: dict[str, Any], schemas_data: list[SchemaFile]) -> None:
console.print("[red]Unable to load the schema:")
if "detail" not in response:
handle_non_detail_errors(response=response)
return
for error in response["detail"]:
loc_path = error.get("loc", [])
if not valid_error_path(loc_path=loc_path):
continue
# if the len of the path is equal to 6, the error is at the root of the object
# if the len of the path is higher than 6, the error is in an attribute or a relationships
schema_index = int(loc_path[2])
node_index = int(loc_path[4]) # <-- crashes here for extensions paths
...
And the path validator at line 116, which lets the malformed path through:
def valid_error_path(loc_path: list[Any]) -> bool:
return len(loc_path) >= 6 and loc_path[0] == "body" and loc_path[1] == "schemas"
valid_error_path does not check that loc_path[3] is "nodes" or "generics", so loc_path[3] == "extensions" slips through and the indexing assumption breaks.
Suggested fix
Branch on whether loc_path[3] == "extensions" and re-anchor the indexing:
def display_schema_load_errors(response: dict[str, Any], schemas_data: list[SchemaFile]) -> None:
console.print("[red]Unable to load the schema:")
if "detail" not in response:
handle_non_detail_errors(response=response)
return
for error in response["detail"]:
loc_path = error.get("loc", [])
if not valid_error_path(loc_path=loc_path):
continue
schema_index = int(loc_path[2])
# Distinguish top-level vs extensions-block error paths.
# Top-level: body/schemas/<si>/nodes|generics/<ni>/<field>
# Extensions: body/schemas/<si>/extensions/nodes|generics|relationships/<ni>/<field>
if loc_path[3] == "extensions":
container = loc_path[4] # 'nodes' / 'generics' / 'relationships'
node_index = int(loc_path[5])
tail = loc_path[6:]
else:
container = loc_path[3] # 'nodes' / 'generics'
node_index = int(loc_path[4])
tail = loc_path[5:]
...
get_node and the downstream len(loc_path) == 6 / > 6 branches need corresponding adjustments (the absolute lengths shift by one for the extensions path).
valid_error_path should additionally accept loc_path[3] in ("nodes", "generics", "extensions") so unrelated server errors don't fall through this codepath.
Component
Python SDK, infrahubctl
Infrahub SDK version
1.20.0
Current Behavior
infrahubctl schema loadcallsinfrahub_sdk.ctl.schema.display_schema_load_errorsto render server-rejected schema validation errors. The function indexesloc_path[2]andloc_path[4]and casts both toint, assuming the loc tuple shape is("body", "schemas", <schema_index>, "nodes"|"generics", <node_index>, ...).When the rejected error originates inside an
extensions:block (per docs.infrahub.app/topics/schema-extensions), the loc tuple has an extra segment:So
loc_path[4]is a string like"generics"instead of the integer node index.int("generics")raises:The traceback replaces the intended human-readable error message — the user never sees what the server actually rejected.
Expected Behavior
The server's rejection should be rendered in the same human-readable format as non-extensions errors, e.g.:
Steps to Reproduce
Environment
infrahub-sdk[all]1.20.0Steps
1. Have a running Infrahub instance with a schema that includes a generic that has
include_in_menu: true(e.g., theDcimGenericDevicefromopsmill/schema-library'sbase/dcim.yml). Any kind whose existing schema metadata you want to override works.2. Author a schema-extension YAML that attempts to override a metadata field on an existing kind:
3. Run
infrahubctl schema load:Actual output (1.20.0)
The user sees no human-readable explanation of why the schema was rejected.
Additional Information
Affected code
infrahub_sdk/ctl/schema.pylines 53–103 (in 1.20.0), functiondisplay_schema_load_errors:And the path validator at line 116, which lets the malformed path through:
valid_error_pathdoes not check thatloc_path[3]is"nodes"or"generics", soloc_path[3] == "extensions"slips through and the indexing assumption breaks.Suggested fix
Branch on whether
loc_path[3] == "extensions"and re-anchor the indexing:get_nodeand the downstreamlen(loc_path) == 6/> 6branches need corresponding adjustments (the absolute lengths shift by one for the extensions path).valid_error_pathshould additionally acceptloc_path[3] in ("nodes", "generics", "extensions")so unrelated server errors don't fall through this codepath.