affaan-m/ECC · error · ContractError
CV effect lacks a valid subject anchor
Error message
CV effect {event.get('effect')} lacks a valid subject anchor What it means
ContractError (f-string) raised when a CV event declares requires_subject_anchor=true but its subject_anchor is not a dict containing all required keys: mode, target, source_ref_sha256, evidence_time, source_duration, lost_policy. The contract requires a structurally complete anchor before further semantic checks run.
Solutions
- Ensure subject_anchor is a dict with all six keys: mode, target, source_ref_sha256, evidence_time, source_duration, lost_policy.
- Use snake_case key names exactly as the contract specifies.
- Emit the anchor from the receipt/reference pipeline so source_ref_sha256 and source_duration are populated from real data.
- Add a pre-validation schema check that reports which required anchor keys are missing.
Example fix
// before
{"effect": "cv_blur", "requires_subject_anchor": true, "subject_anchor": {"mode": "object_track"}}
// after
{"effect": "cv_blur", "requires_subject_anchor": true, "subject_anchor": {"mode": "object_track", "target": "subject_0", "source_ref_sha256": "<digest>", "evidence_time": 1.2, "source_duration": 10.0, "lost_policy": "disable_effect_until_track_recovers"}} Defensive patterns
Strategy: type-guard
Validate before calling
REQUIRED_ANCHOR_KEYS = {"mode", "target", "source_ref_sha256", "evidence_time", "source_duration", "lost_policy"}
for event in recipe["events"]:
anchor = event.get("subject_anchor")
if not isinstance(anchor, dict) or not REQUIRED_ANCHOR_KEYS.issubset(anchor):
raise ValueError(f"{event.get('effect')}: subject_anchor incomplete") Type guard
def is_valid_anchor_shape(anchor) -> bool:
required = {"mode", "target", "source_ref_sha256", "evidence_time", "source_duration", "lost_policy"}
return isinstance(anchor, dict) and required.issubset(anchor) Try / catch
try:
validate_effect_recipe(recipe, reference_durations)
except ContractError as exc:
if "lacks a valid subject anchor" in str(exc):
missing = REQUIRED_ANCHOR_KEYS - set(event["subject_anchor"] or {})
raise ValueError(f"anchor missing keys: {missing}") from exc
raise Prevention
- Emit anchors from a single typed constructor that fills all six keys
- Validate anchors against a JSON Schema before bundle submission
- Never build anchors by hand; derive them from receipt data
- Keep key names snake_case and centralized in one constants module
When it happens
Trigger: Calling validate_effect_recipe with subject_anchor set to null, a non-dict (e.g. string or list), or a dict missing one or more of the six required keys (commonly forgetting source_duration or lost_policy).
Common situations: Anchors partially filled in from a template; fields dropped during JSON round-tripping; upstream tooling that emits anchor as a flat structure instead of a nested dict; typos in key names such as sourceRefSha256.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- has invalid style evidence
- -32602
- anchor evidence source duration is not bound to its receipt…
- artifact path must be a non-empty relative path
- assets must be a nonempty list
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/1eb998a370f22f02.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:238
if len(set(intervals)) <= 1:
raise ContractError("stochastic schedule is periodic; intervals must vary")
for period in range(1, len(intervals) // 2 + 1):
if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):
raise ContractError("stochastic schedule is periodic; repeating interval cycle")
if recipe.get("periodic") is not False:
raise ContractError("effect recipe must explicitly declare periodic=false")
for event in events:
cv_effect = str(event.get("effect", "")).startswith("cv_")
if cv_effect and event.get("requires_subject_anchor") is not True:
raise ContractError(f"CV effect {event.get('effect')} must require a subject anchor")
if event.get("requires_subject_anchor"):
anchor = event.get("subject_anchor")
required = {
"mode", "target", "source_ref_sha256", "evidence_time",
"source_duration", "lost_policy",
}
if not isinstance(anchor, dict) or not required.issubset(anchor):
raise ContractError(f"CV effect {event.get('effect')} lacks a valid subject anchor")
if anchor.get("mode") not in {"object_track", "point_track", "segmentation_track"}:
raise ContractError(f"CV effect {event.get('effect')} has an invalid subject anchor")
if anchor.get("lost_policy") != "disable_effect_until_track_recovers":
raise ContractError(f"CV effect {event.get('effect')} must fail closed on anchor loss")
_validate_media_time(
anchor.get("evidence_time"), anchor.get("source_duration"),
label="anchor evidence time",
)
if reference_durations is not None:
digest = anchor.get("source_ref_sha256")
expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None
if expected_duration is None or anchor.get("source_duration") != expected_duration:
raise ContractError("anchor evidence source duration is not bound to its receipt reference")
for event in events:
placement = event.get("placement")
if not isinstance(placement, dict) or not {"safe_area", "max_coverage", "occlusion_policy"}.issubset(placement):
raise ContractError(f"effect {event.get('effect')} lacks placement constraints")
View on GitHub (pinned to 8321021c54)