affaan-m/ECC · error · ValueError

workflow schema_version must be 1

Error message

workflow schema_version must be 1

What it means

run_workflow only accepts config documents with schema_version exactly 1. Any other value (missing counts as absent and fails this check too since != 1) is rejected so old or future config formats fail loudly.

Solutions

  1. Add "schema_version": 1 to the workflow config
  2. If migrating from another schema version, convert the config to the v1 format
  3. Ensure the value is the JSON number 1, not the string "1"

Example fix

// before
{ "genres": [ ... ] }
// after
{ "schema_version": 1, "genres": [ ... ] }
Defensive patterns

Strategy: validation

Validate before calling

if config.get("schema_version") != 1:
    raise SystemExit("config schema_version must be exactly 1 (number, not string)")

Type guard

def is_v1_config(config: dict) -> bool:
    return config.get("schema_version") == 1 and isinstance(config.get("schema_version"), int)

Try / catch

try:
    run_workflow(config)
except ValueError as e:
    if "schema_version" in str(e):
        config["schema_version"] = 1
        run_workflow(config)
    else:
        raise

Prevention

When it happens

Trigger: A config JSON/YAML passed to run_workflow lacks the "schema_version" key or has a value other than 1 (e.g. 2, "1").

Common situations: Hand-written configs forgetting the field; copying configs from a newer/older tool version; YAML parsing "1" as string in some writers.

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/daac83ca63629f69. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/workflow.py:537

        },
    }


def run_workflow(config_path: str | Path, out_dir: str | Path, *, probe: Probe | None = None) -> dict[str, Any]:
    """Execute the deterministic offline contract and return its receipt."""
    config_path = Path(config_path)
    out_dir = Path(out_dir)
    config = json.loads(config_path.read_text(encoding="utf-8"))
    probe = probe or probe_media

    def resolve_input(raw_path: str) -> Path:
        candidate = Path(raw_path).expanduser()
        if not candidate.is_absolute():
            candidate = config_path.parent / candidate
        return Path(os.path.abspath(candidate))

    if config.get("schema_version") != 1:
        raise ValueError("workflow schema_version must be 1")
    if config.get("dry_run", True) is not True:
        raise ValueError("workflow requires dry_run=true; provider execution is disabled")
    source_policy = config.get("source_availability_policy", "allow_unavailable")
    if source_policy not in {"allow_unavailable", "require_available"}:
        raise ValueError("source_availability_policy must be allow_unavailable or require_available")
    genres = sorted(config.get("genres", []), key=lambda item: item["number"])
    if not genres:
        raise ValueError("workflow needs at least one numbered genre")

    output = _SafeOutput(out_dir)
    output.prepare(("genres", "manifests", "resolve"))

    references: list[dict[str, Any]] = []
    specs: list[dict[str, Any]] = []
    manifests: dict[str, dict[str, Any]] = {
        modality: {
            "schema_version": 1,
            "modality": modality,

View on GitHub (pinned to 8321021c54)