openmediavault/openmediavault · error · SchemaException
No 'properties' attribute defined at
Error message
No 'properties' attribute defined at '%s'.
What it means
Datamodel._walk_schema requires every node with type 'object' to define a 'properties' attribute, because it iterates schema['properties'] to recurse into child nodes. An object node without 'properties' is treated as an untraversable malformed schema and raises json.SchemaException with the failing path. Like error 150 this is a schema-definition bug, not bad data.
Solutions
- Locate the path from the message in the datamodel schema and add a 'properties' object listing the child fields (use "properties": {} only if intentionally empty and the walker should not recurse).
- Run the schema through openmediavault.json.Schema validation in a unit test to catch structural gaps before shipping.
- Rebuild/re-register the plugin schema (dpkg install or omv-mkconf) so the fixed schema is loaded.
- Diff the schema against a known-good upstream version to see what got lost.
Example fix
// before
"notification": { "type": "object" }
// after
"notification": { "type": "object", "properties": { "enabled": { "type": "boolean" } } } Defensive patterns
Strategy: validation
Validate before calling
def validate_object_schemas(schema):
for key, node in schema.items():
if isinstance(node, dict):
if node.get("type") == "object" and "properties" not in node:
raise ValueError(f"Object '{key}' missing 'properties'")
validate_object_schemas(node) Type guard
def has_properties(node: dict) -> bool:
return isinstance(node, dict) and node.get("type") == "object" and "properties" in node Try / catch
try:
datamodel.walk_schema(path, callback)
except openmediavault.json.SchemaException as e:
logging.error("Malformed datamodel schema: %s", e) Prevention
- Never declare an object node without a 'properties' map in datamodel schemas.
- Add CI tests walking all datamodel schemas to surface structural gaps.
- Keep 'properties': {} explicitly when an object is intentionally empty.
- Diff schemas against upstream versions when upgrading plugins.
When it happens
Trigger: Datamodel.walk_schema() (called by DatabaseQuery walks and ConfigObject) reaches a schema node {"type": "object"} with no 'properties' key — typically an empty or truncated object definition in the datamodel schema.
Common situations: Plugin authors declaring a nested object but forgetting its properties block; schema generated/merged by tooling that strips empty 'properties'; hand-editing config.xml.rng-derived schemas and dropping the properties map.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- The attribute 'type' must not be an array at
- No 'type' attribute defined at
- No 'items' attribute defined at
- : No 'items' attribute defined.
- DatamodelNotFoundException
AI-assisted analysis of openmediavault/openmediavault@dce610eb66 (2026-09-15).
Data as JSON: /api/errors/8bc13d0699cad671.
Report an issue: GitHub.
Appendix: source
Thrown at deb/openmediavault/usr/lib/python3/dist-packages/openmediavault/config/datamodel.py:335
if not "type" in schema:
raise openmediavault.json.SchemaException(
"No 'type' attribute defined at '%s'." % path
)
if "array" == schema['type']:
# Validate the node.
if not "items" in schema:
raise openmediavault.json.SchemaException(
"No 'items' attribute defined at '%s'." % path
)
# Call the callback function.
if callback(self, name, path, schema, user_data) is False:
return
# Process the array items.
_walk_schema(name, path, schema['items'], callback, user_data)
elif "object" == schema['type']:
# Validate the node.
if not "properties" in schema:
raise openmediavault.json.SchemaException(
"No 'properties' attribute defined at '%s'." % path
)
# Call the callback function.
if callback(self, name, path, schema, user_data) is False:
return
# Process the object properties.
for prop_name, prop_schema in schema['properties'].items():
# Build the property path. Take care that a valid path
# is generated. To ensure this, empty parts are removed.
prop_path = ".".join([x for x in [path, prop_name] if x])
# Process the property node.
_walk_schema(
prop_name, prop_path, prop_schema, callback, user_data
)
else:
callback(self, name, path, schema, user_data)
_walk_schema(View on GitHub (pinned to dce610eb66)