Skip to main content

Overview

Infrahub enforces strict schema validation to ensure data integrity and consistency. This guide explains the validation rules, constraints, and how to handle validation errors.

Validation Levels

Schema validation occurs at multiple levels:
1

Schema Definition Validation

Validates the YAML schema structure itself:
  • Required fields are present
  • Data types are correct
  • References to other schemas exist
  • No circular dependencies
2

Data Integrity Validation

Validates data against the schema:
  • Required attributes have values
  • Values match the attribute kind
  • Unique constraints are enforced
  • Relationships point to valid nodes
3

Migration Validation

Validates schema changes:
  • New mandatory fields have defaults
  • Existing data is compatible
  • Relationship changes are valid

Uniqueness Constraints

Single Field Uniqueness

Enforce uniqueness on a single attribute:
nodes:
  - name: Device
    namespace: Infra
    attributes:
      - name: name
        kind: Text
        unique: true  # No two devices can have the same name
      - name: serial_number
        kind: Text
        unique: true
        optional: true  # Unique when provided, but not required

Composite Uniqueness

Enforce uniqueness across multiple fields:
nodes:
  - name: Interface
    namespace: Infra
    uniqueness_constraints:
      - ["device", "name__value"]  # Unique combination of device + interface name
    attributes:
      - name: name
        kind: Text
    relationships:
      - name: device
        peer: InfraDevice
        cardinality: one
Composite uniqueness is useful for child objects that must be unique within their parent context.

Uniqueness Validation Example

nodes:
  - name: Rack
    namespace: Location
    uniqueness_constraints:
      - ["site", "name__value"]  # Rack name must be unique per site
    human_friendly_id: ["site__name__value", "name__value"]
    attributes:
      - name: name
        kind: Text
    relationships:
      - name: site
        peer: LocationSite
        cardinality: one
        optional: false
This allows:
  • Site A: Rack “R1”
  • Site B: Rack “R1”
But prevents:
  • Site A: Rack “R1” (twice)

Attribute Validation

Required vs Optional Attributes

attributes:
  - name: name
    kind: Text
    optional: false  # Default, must have a value

Text Attribute Validation

attributes:
  - name: hostname
    kind: Text
    parameters:
      regex: "^[a-z0-9-]+$"  # Only lowercase, numbers, and hyphens
      min_length: 3
      max_length: 63
Validation rules:
  • regex: Pattern the value must match
  • min_length: Minimum character length
  • max_length: Maximum character length

Number Attribute Validation

attributes:
  - name: vlan_id
    kind: Number
    parameters:
      min_value: 1
      max_value: 4094
  - name: port_number
    kind: Number
    parameters:
      min_value: 1
      max_value: 65535
Validation rules:
  • min_value: Minimum numeric value
  • max_value: Maximum numeric value

Enum Validation

attributes:
  - name: device_type
    kind: Text
    enum: ["router", "switch", "firewall"]  # Only these values allowed
  - name: lacp_mode
    kind: Text
    enum: ["Active", "Passive", "Disabled"]
    default_value: "Passive"
attributes:
  - name: status
    kind: Dropdown
    choices:  # Must provide choices for Dropdown
      - name: active
        label: Active
      - name: maintenance
        label: Maintenance
    default_value: "active"  # Must be one of the choices
Dropdown requires choices: Omitting the choices property for a Dropdown attribute will cause validation to fail.

Relationship Validation

Cardinality Constraints

relationships:
  - name: primary_address
    peer: IpamIPAddress
    cardinality: one
    optional: true

Relationship Kind Validation

Different relationship kinds have different validation rules:
# Standard relationship
relationships:
  - name: site
    peer: LocationSite
    kind: Attribute
    cardinality: one

Common Parent Validation

Ensure related objects share a common parent:
relationships:
  - name: lag
    peer: InfraLagInterface
    cardinality: one
    optional: true
    kind: Attribute
    common_parent: device  # LAG must be on the same device

Human-Friendly ID Validation

Human-friendly IDs create readable identifiers:
nodes:
  - name: Interface
    namespace: Infra
    human_friendly_id: ["device__name__value", "name__value"]
    uniqueness_constraints:
      - ["device", "name__value"]
Rules:
  • Fields in human_friendly_id should ensure uniqueness
  • Use __value suffix for attributes
  • Can traverse relationships (e.g., device__name__value)
  • Typically matches uniqueness_constraints

Hierarchical Validation

For tree-structured data:
generics:
  - name: Generic
    namespace: Location
    hierarchical: true

nodes:
  - name: Continent
    namespace: Location
    inherit_from:
      - LocationGeneric
    parent: ""  # Root level, no parent
    children: "LocationCountry"
  
  - name: Country
    namespace: Location
    inherit_from:
      - LocationGeneric
    parent: "LocationContinent"  # Must have Continent parent
    children: "LocationSite"
  
  - name: Site
    namespace: Location
    inherit_from:
      - LocationGeneric
    parent: "LocationCountry"  # Must have Country parent
    children: ""
Validation rules:
  • Parent node must exist for child creation
  • Parent-child relationships must match schema definition
  • Cannot create circular hierarchies

Inheritance Validation

When using inherit_from:
generics:
  - name: Generic
    namespace: Organization
    attributes:
      - name: name
        kind: Text
        unique: true

nodes:
  - name: Manufacturer
    namespace: Organization
    inherit_from:
      - OrganizationGeneric  # Inherits name attribute
    attributes:
      - name: country
        kind: Text
Rules:
  • Referenced generic/node must exist
  • Can inherit from multiple sources
  • Child can override inherited properties
  • Cannot create circular inheritance

Schema Change Validation

Adding Mandatory Attributes

When adding non-optional attributes to existing schemas, you must provide a default_value:
# ✅ Correct - has default_value
attributes:
  - name: new_field
    kind: Text
    optional: false
    default_value: "default"

# ❌ Incorrect - missing default_value for existing schema
attributes:
  - name: new_field
    kind: Text
    optional: false  # Will fail if schema has existing data

Removing Attributes

Removing attributes is allowed but:
  • Existing data is preserved in the database
  • Attribute becomes inaccessible via API
  • Consider deprecation workflow for production

Changing Attribute Types

Changing kind may fail if incompatible:
# Before
attributes:
  - name: port
    kind: Text

# After - may fail if existing values aren't numeric
attributes:
  - name: port
    kind: Number

Validation Error Messages

Error: Uniqueness constraint violation for Device.nameCause: Attempting to create/update an object with a value that violates uniquenessSolution: Use a different value or update the existing object
Error: Required attribute 'name' is missingCause: Creating an object without providing a mandatory attributeSolution: Provide a value for all non-optional attributes
Error: Cannot assign multiple values to cardinality:one relationshipCause: Trying to assign multiple objects to a one-to-one relationshipSolution: Assign only a single object
Error: Value 'invalid' not in enum ['option1', 'option2']Cause: Providing a value not in the enum listSolution: Use one of the defined enum values

Testing Schema Validation

Validate schemas before deployment:
from infrahub_sdk import InfrahubClient

client = InfrahubClient(address="http://localhost:8000")

# Test schema in a branch first
branch = await client.branch.create(
    branch_name="test-schema",
    description="Testing schema validation"
)

try:
    result = await client.schema.load(
        schemas=["test-schema.yml"],
        branch="test-schema"
    )
    print("Schema is valid")
except Exception as e:
    print(f"Validation error: {e}")

Best Practices

Define Constraints Early

Set up uniqueness and validation rules from the start to prevent data issues

Use Meaningful Defaults

Provide sensible default values for optional attributes

Test Schema Changes

Always test schema modifications in a branch before applying to main

Document Constraints

Document why specific validation rules exist for future maintainers

Next Steps

Create Schema

Learn how to define schemas with proper validation

Relationships

Understand relationship constraints and validation

Import Schema

Load and test your validated schemas

Working with Branches

Test schema changes safely in branches

Build docs developers (and LLMs) love