calesthio/OpenMontage · error · CheckpointValidationError
GATE VIOLATION: stage {stage!r} requires human approval ({ga
Error message
GATE VIOLATION: stage {stage!r} requires human approval ({gate_source}) but status='completed' was written without human_approved=True. Correct protocol: write status='awaiting_human', present the artifact summary to the user, END YOUR TURN, and only after the user approves re-write with status='completed', human_approved=True. What it means
Raised by lib/checkpoint.py when a checkpoint for a stage that requires human approval (via human_approval_default: true in the pipeline manifest, or human_approval_required=True passed by the caller) is written with status='completed' but without human_approved=True. The checkpoint system enforces a human-in-the-loop gate: the agent must first persist status='awaiting_human', present the artifact summary, end its turn, and only after explicit user approval write status='completed' with human_approved=True. This is a deliberate protocol violation guard, not a data corruption bug.
Source
Thrown at lib/checkpoint.py:487
# gates on human approval; a caller may gate MORE strictly (e.g. a
# manual_all checkpoint policy) but never less. A gated stage can only be
# written "completed" with explicit evidence of approval
# (human_approved=True). Skipping a gate is a hard error.
#
# Enforcement happens at write time only: pre-existing checkpoints written
# before gating (or by hand) still read as completed — deliberate
# back-compat so in-flight and legacy projects keep resuming.
manifest_gate = _stage_requires_approval(pipeline_type, stage)
gated = bool(manifest_gate) or human_approval_required
if gated:
human_approval_required = True
if status == "completed" and not human_approved:
gate_source = (
f"human_approval_default: true in the {pipeline_type!r} manifest"
if manifest_gate
else "human_approval_required=True was passed by the caller"
)
raise CheckpointValidationError(
f"GATE VIOLATION: stage {stage!r} requires human approval "
f"({gate_source}) but status='completed' was written without "
f"human_approved=True. Correct protocol: write "
f"status='awaiting_human', present the artifact summary to the "
f"user, END YOUR TURN, and only after the user approves "
f"re-write with status='completed', human_approved=True."
)
_enforce_stage_prerequisites(
pipeline_dir,
project_id,
pipeline_type,
stage,
status,
)
checkpoint = {
"version": "1.0",View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Rewrite the checkpoint with status='awaiting_human' first, present the artifact summary to the user, and end the turn.
- After the user approves, write the checkpoint again with status='completed' and human_approved=True.
- If the gate is intentional and the caller is authorized, pass human_approved=True together with status='completed' only when a real human approval exists.
- If the stage should not be gated, edit the pipeline manifest and remove human_approval_default: true for that stage (a user/product decision, not an agent one).
Example fix
# before write_checkpoint(stage="final_review", status="completed") # after write_checkpoint(stage="final_review", status="awaiting_human") # ... present artifact summary, END TURN ... # after user approval: write_checkpoint(stage="final_review", status="completed", human_approved=True)
Defensive patterns
Strategy: validation
Validate before calling
from lib.pipeline_loader import load_pipeline_readonly, get_stage_human_approval_default
def stage_is_gated(pipeline_type: str, stage: str) -> bool:
try:
manifest = load_pipeline_readonly(pipeline_type)
except Exception:
return False
return bool(get_stage_human_approval_default(manifest, stage))
# before writing 'completed':
if stage_is_gated(pipeline_type, stage) and not human_approved:
write_checkpoint(stage=stage, status="awaiting_human") # then end turn Type guard
def can_complete_stage(pipeline_type: str, stage: str, human_approved: bool) -> bool:
"""True only when the stage is ungated OR a human has approved."""
return human_approved or not stage_is_gated(pipeline_type, stage) Try / catch
try:
write_checkpoint(stage=stage, status="completed", human_approved=approved)
except CheckpointValidationError as e:
if "GATE VIOLATION" in str(e):
write_checkpoint(stage=stage, status="awaiting_human")
present_artifact_summary()
return # end turn; complete only after user approval
raise Prevention
- Treat gated stages as a two-phase write: awaiting_human first, completed+human_approved=True second.
- Check human_approval_default in the pipeline manifest before starting a stage so the pause is planned, not discovered.
- Never auto-set human_approved=True; only mirror an explicit user approval event.
- Keep the gate violation message as the protocol reminder: present summary, end turn, then complete.
When it happens
Trigger: Calling the checkpoint write API with status='completed' for a stage whose manifest entry has human_approval_default: true (e.g. final_review in a gated pipeline), or passing human_approval_required=True while omitting human_approved=True. Also triggered when an agent skips the awaiting_human intermediate write and tries to complete a gated stage in a single call.
Common situations: Agents automating a full pipeline end-to-end without pausing; new pipeline manifests that enable human_approval_default on stages previously auto-completed; legacy code written before the gating was added that resumes in-flight projects and writes completed directly.
Related errors
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/78d6d179dab909a4.
Report an issue: GitHub.