calesthio/OpenMontage · error · CheckpointValidationError

Invalid stage: {stage!r} for pipeline {pipeline_type!r}. Val

Error message

Invalid stage: {stage!r} for pipeline {pipeline_type!r}. Valid stages: {sorted(valid_stages)}

What it means

_probe_local_audio_duration was given a path that does not exist when ffprobe runs. Usually the file existed during earlier validation but disappeared before probing, or the temp-file write path failed; it is a guard against TOCTOU/missing-file races in audio duration validation.

Source

Thrown at lib/checkpoint.py:177

def validate_checkpoint(checkpoint: dict[str, Any]) -> None:
    """Validate checkpoint structure and canonical artifact payloads.

    Uses pipeline_type (if present) to resolve the valid stage list.
    Falls back to ALL_KNOWN_STAGES when pipeline_type is absent.
    """
    stage = checkpoint.get("stage")
    status = checkpoint.get("status")
    artifacts = checkpoint.get("artifacts")
    pipeline_type = checkpoint.get("pipeline_type")

    valid_stages = (
        set(get_pipeline_stages(pipeline_type)) if pipeline_type
        else ALL_KNOWN_STAGES
    )

    if not isinstance(stage, str) or stage not in valid_stages:
        raise CheckpointValidationError(
            f"Invalid stage: {stage!r} for pipeline {pipeline_type!r}. "
            f"Valid stages: {sorted(valid_stages)}"
        )
    if not isinstance(status, str):
        raise CheckpointValidationError(f"Invalid status: {status!r}")
    if not isinstance(artifacts, dict):
        raise CheckpointValidationError("Checkpoint artifacts must be a dictionary")

    _validate_artifacts_for_stage(stage, status, artifacts)

    try:
        jsonschema.validate(instance=checkpoint, schema=_load_checkpoint_schema())
    except jsonschema.ValidationError as exc:
        raise CheckpointValidationError(f"Checkpoint failed schema validation: {exc.message}") from exc


def _checkpoint_path(pipeline_dir: Path, project_id: str, stage: str) -> Path:
    return pipeline_dir / project_id / f"checkpoint_{stage}.json"

View on GitHub (pinned to 95e1c3d0ab)

Solutions

  1. Confirm the file exists immediately before the call and keep it alive for the duration of the request.
  2. Copy the reference audio into a directory your process owns exclusively.
  3. Retry the generation step end-to-end if a concurrent cleanup is the culprit.
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path
p = Path(ref_audio)
assert p.is_file(), p  # check immediately before the call
# keep the file on disk until the request finishes

Try / catch

try:
    tool.run(inputs)
except ValueError as e:
    if "does not exist" in str(e):
        restore_or_recreate(ref_audio)  # re-materialize the file, retry once
    else:
        raise

Prevention

When it happens

Trigger: Another process deletes/moves the audio file between reference validation and probing; a NamedTemporaryFile cleanup (finally: unlink) racing a reuse of temp_path; passing a path that was never created because an earlier step silently failed.

Common situations: Concurrent pipelines cleaning a shared tmp directory; retry logic reusing a stale path after cleanup; sandboxed environments where the file lands somewhere else.

Related errors


AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15). Data as JSON: /api/errors/bfe71dd31db86b79. Report an issue: GitHub.