affaan-m/ECC · error · ContractError

CV effect has an invalid subject anchor

Error message

CV effect {event.get('effect')} has an invalid subject anchor

What it means

ContractError (f-string) raised when the subject anchor dict is structurally complete but its 'mode' value is not one of the allowed tracking modes: object_track, point_track, or segmentation_track. The contract restricts anchors to these three track types.

Solutions

  1. Set mode to exactly one of: object_track, point_track, segmentation_track.
  2. Map your tracker's output type to the closest contract mode before validating.
  3. Add an enum check in your generator against the same set the contract uses.
  4. Catch ContractError and print the invalid mode value to speed up authoring fixes.

Example fix

// before
anchor = {..., "mode": "bounding_box", ...}
// after
anchor = {..., "mode": "object_track", ...}
Defensive patterns

Strategy: validation

Validate before calling

VALID_MODES = {"object_track", "point_track", "segmentation_track"}
if anchor.get("mode") not in VALID_MODES:
    raise ValueError(f"anchor mode must be one of {sorted(VALID_MODES)}")

Type guard

def has_valid_track_mode(anchor) -> bool:
    return isinstance(anchor, dict) and anchor.get("mode") in {"object_track", "point_track", "segmentation_track"}

Try / catch

try:
    validate_effect_recipe(recipe, reference_durations)
except ContractError as exc:
    if "invalid subject anchor" in str(exc):
        anchor["mode"] = normalize_track_mode(anchor["mode"])
    else:
        raise

Prevention

When it happens

Trigger: Calling validate_effect_recipe with an anchor whose mode is e.g. "bbox", "face", "object", "tracking", or a typo like "object_tracks". Any value outside the three-element set fails.

Common situations: Using mode names from a different tracking library's vocabulary; typos or pluralization mistakes; older recipe formats that used a different mode enum before the contract standardized the three values.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/ec6e7c85c22797e3. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/contract.py:240

    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")


def validate_provenance(payload: dict[str, Any]) -> None:

View on GitHub (pinned to 8321021c54)