PackSchemaViolation¶
Data passed to graph.add_object or graph.add_relation doesn't
match the schema declared by a loaded pack. The framework validates
every add against the pack's declared types so downstream behaviors
and pattern matches can rely on the shape — a malformed add would
silently corrupt views and patterns that depend on the declared
fields.
This is the lone runtime-shape leaf under
PackError. It fires at
add-time, after pack load — distinct from
pack-conflict-error and
pack-version-conflict-error,
which fire at pack-load time.
Multi-inherits ValueError for back-compat — code that catches the
builtin around graph.add_object / add_relation continues to work.
Quick fix by shape¶
The error message names the specific violation inline (the offending type, the offending data, and the pack that declared the schema). The three call shapes that produce this error each have a different fix:
Object data doesn't match the declared schema¶
The most common case. Recovery is fixing the dict shape — usually a missing required field, a wrong field type, or an extra field a strict schema rejects.
# Inspect the pack's declared schema for the object type:
from activegraph.packs.diligence import pack as p
schema = next(ot for ot in p.object_types if ot.name == "claim").schema
print(schema.model_json_schema())
# Then adjust the data to match.
graph.add_object("claim", {
"text": "...",
"confidence": 0.85, # the missing field, now included
})
Relation source isn't an allowed type¶
The pack declared which object types can sit on the source side of a relation type. The fix is either passing a source of an allowed type or declaring the new type on the relation:
# Pass a source of an allowed type (the error names which are allowed).
graph.add_relation(claim_id, evidence_id, "supports")
# Or, if the constraint is wrong, relax the relation type's
# declaration in the pack:
RelationType(
name="supports",
source_types=["claim", "memo"], # ← add the new source type
target_types=["evidence"],
)
Relation target isn't an allowed type¶
Symmetric with source — same fix on the other endpoint. The error names which types are allowed on the target side.
Multi-pack note¶
The error message names the pack that declared the violated schema.
In a multi-pack runtime, the constraint that fired might not come
from your own pack — check the named pack's declaration, not just
the one you're working in. The factory methods carry pack_name
through the context dict for programmatic introspection:
try:
graph.add_object("claim", data)
except PackSchemaViolation as e:
print(e.context["pack"]) # which pack declared the schema
print(e.context["object_type"]) # or relation_type, with "side"
How to diagnose¶
The error names the offending type and the validation detail:
PackSchemaViolation: object_type 'claim': schema validation failed
What failed:
`graph.add_object('claim', data=...)` was rejected because the
data did not match the pack's declared schema for 'claim'
(declared by pack 'diligence').
Validation error:
1 validation error for Claim
confidence: Field required ...
From code:
try:
graph.add_object("claim", data)
except PackSchemaViolation as e:
print(e.context["object_type"]) # 'claim'
print(e.context["pack"]) # 'diligence'
print(e.context["validation_error"]) # the full Pydantic error
For relation violations, the context includes relation_type,
the offending type, the allowed list, and side ("source" or
"target").
When does this fire¶
At graph.add_object and graph.add_relation, after a pack with a
declared schema for the affected type has loaded. The check is
post-load: objects created before the pack was loaded aren't
retroactively validated (CONTRACT v0.9 #5 — the load-order
asymmetry).
The check runs synchronously at the add site. The mutation never lands if validation fails — the graph is unchanged after the exception fires.
Why the framework refuses to continue¶
Packs declare object schemas to constrain what shape of data can
flow into objects of that type. The runtime validates every
add_object against the schema so downstream behaviors can rely on
the shape — a malformed add would silently corrupt views and
pattern matches that depend on the declared fields. Relation type
constraints serve the same purpose on the structural side:
out-of-spec relations would cause pattern matches to silently miss
or misfire.
Refusing the add is the framework's way of asking the caller to fix the data or the schema, not to discover the wrong-shape data later when a downstream behavior fires on it.
See failure-model for the
broader principle.
What's related¶
pack-conflict-error— fires at pack load time when two packs declare the same canonical symbol; distinct from this page's runtime-shape errors.pack-version-conflict-error— load-time sibling for same-pack-two-versions.- Authoring packs — the
canonical reference for declaring
ObjectTypeandRelationTypeschemas in a pack.