affaan-m/ECC · error · ValueError

built an invalid spec

Error message

built an invalid spec: {problems}

What it means

build_spec constructs a taste-distillation spec and validates it against SPEC_SCHEMA before returning it. If the assembled spec fails schema validation, it raises ValueError with the list of schema problems. This is an internal invariant check: the builder itself produced something invalid, indicating a bug or bad profile data feeding it.

Solutions

  1. Read the `problems` list in the message — it names the exact failing field and reason
  2. Validate the input profile against the expected profile schema before calling distill_local/build_spec
  3. Fix the offending field in the profile (types/enums/required keys) per the problems output
  4. If you edited SPEC_SCHEMA or build_spec locally, revert them to a consistent pair

Example fix

// before: profile with bad field
{"budget": "cheap"}  # schema expects number
// after
{"budget": 3.0}
# then: distill_local(profile)
Defensive patterns

Strategy: try-catch

Validate before calling

from tasteforge.distill import schema
def profile_buildable(profile: dict) -> bool:
    try:
        spec = build_spec(profile)
        return schema.validate(spec, schema.SPEC_SCHEMA) == []
    except ValueError:
        return False

Type guard

def is_valid_profile(p) -> bool:
    return isinstance(p, dict) and all(isinstance(v, (str, int, float, bool, type(None))) for v in p.values())

Try / catch

try:
    spec = build_spec(profile)
except ValueError as e:
    print(e)  # message lists exact schema problems; fix profile fields accordingly
    spec = None

Prevention

When it happens

Trigger: Calling build_spec (via distill_local) with profile/pack data that causes an invalid field — e.g. wrong types in the taste profile, a missing required key the builder copies through, or a modified SPEC_SCHEMA that the builder no longer satisfies.

Common situations: Upstream profile JSON with unexpected shapes (string numbers, null fields), locally edited schemas or builder code drifting apart, or passing a StylePack of the wrong shape.

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


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/distill.py:77

    """Assemble a schema-valid spec from look constraints (offline)."""
    spec: dict[str, Any] = {}
    for key in _SPEC_STRING_KEYS:
        value = look.get(key)
        spec[key] = value.strip() if isinstance(value, str) else ""
    for key in _SPEC_LIST_KEYS:
        value = look.get(key)
        spec[key] = [str(v) for v in value] if isinstance(value, list) else []

    spec["source"] = {
        "pack": pack_name or "",
        "generated": _utc_now(),
        "dry_run": True,
        "provider": "none",
        "grounding_used": grounding_used,
    }
    problems = schema.validate(spec, schema.SPEC_SCHEMA)
    if problems:
        raise ValueError(f"built an invalid spec: {problems}")
    return spec


def distill_local(profile: dict[str, Any],
                  sp: pack_mod.StylePack | None = None) -> dict[str, Any]:
    """Deterministic offline distillation of a taste profile.

    The output carries dry-run semantics from the recovered implementation:
    ``dry_run: true`` and ``provider: none`` mean no vision model ran and no
    claim of live distillation is made. When a pack with grade/cadence
    metadata is supplied, its measured ground truth is embedded for the
    operator (and any future authorized VLM call) to consume.
    """
    look = dict(profile.get("constraints", {}).get("look", {}))

    grounding_used = False
    grounding_text = ""
    if sp is not None:

View on GitHub (pinned to 8321021c54)