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
- Read the `problems` list in the message — it names the exact failing field and reason
- Validate the input profile against the expected profile schema before calling distill_local/build_spec
- Fix the offending field in the profile (types/enums/required keys) per the problems output
- 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
- Validate taste profiles against the profile schema before distillation
- Avoid local edits that desynchronize build_spec and SPEC_SCHEMA
- Parse profile JSON strictly so numbers stay numbers and nulls are explicit
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
- spec.schedule must be an array of six-cell rows
- spec.schedule[ ] must be a dense six-cell array
- -32602
- 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/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)