can1357/oh-my-pi · error · ManualTriageConflict

ManualTriageConflict(delivery, existing.state)

Error message

ManualTriageConflict(delivery, existing.state)

What it means

ManualTriageConflict raised by enqueue_manual_triage when a previous triage event with the same delivery id is still active — i.e. its recorded state is "queued" or "running". The function refuses to enqueue a duplicate of an in-flight run.

Source

Thrown at python/robomp/src/manual_triage.py:100

            "full_name": repo.full_name,
            "default_branch": repo.default_branch,
            "clone_url": repo.clone_url,
            "private": repo.private,
        },
    }


async def enqueue_manual_triage(*, db: Database, github: GitHubBackend, repo_full: str, number: int) -> str:
    """Fetch the issue from GitHub and queue it for the worker pool.

    Returns the delivery_id. A row may already exist from a previous manual
    triage; inactive rows are replaced so the fresh payload (and reset attempt
    counter) wins. Active rows are left intact.
    """
    delivery = manual_delivery_id(repo_full, number)
    existing = db.get_event(delivery)
    if existing is not None and existing.state in ("queued", "running"):
        raise ManualTriageConflict(delivery, existing.state)

    payload = await build_issues_opened_payload(github, repo_full, number)
    replaced = db.replace_event_if_state_in(
        delivery_id=delivery,
        event_type="issues",
        repo=repo_full,
        issue_key=issue_key(repo_full, number),
        payload=payload,
        state="queued",
        allowed_existing_states=INACTIVE_EVENT_STATES,
    )
    if not replaced:
        current = db.get_event(delivery)
        state = current.state if current is not None else "active"
        raise ManualTriageConflict(delivery, state)
    return delivery

View on GitHub (pinned to 9690622007)

Solutions

  1. Wait for the existing run to reach a terminal state (done/failed/skipped) before re-triggering
  2. Use await_terminal_state(delivery_id) to wait, or poll the event state
  3. If a stale run is stuck, reset/force-close the existing event row, then re-enqueue

Example fix

// before: unguarded re-trigger
await enqueue_manual_triage(github, db, repo, num)
// after: wait out any active run first
try:
    await await_terminal_state(db, delivery_id)
except ManualTriageTimeout:
    pass
await enqueue_manual_triage(github, db, repo, num)
Defensive patterns

Strategy: try-catch

Validate before calling

existing = db.get_event(manual_delivery_id(repo_full, number))
if existing is not None and existing.state in ("queued", "running"):
    raise RuntimeError(f"triage already {existing.state} for {repo_full}#{number}")

Try / catch

try:
    delivery = await enqueue_manual_triage(github, db, repo_full, number)
except ManualTriageConflict as e:
    log.info("triage already %s; reusing delivery %s", e.args, e.args[0])
    delivery = e.args[0]

Prevention

When it happens

Trigger: Calling enqueue_manual_triage (via _go or api_trigger) twice for the same repo#issue before the first run finishes.

Common situations: Double-clicking the triage trigger in the dashboard, re-running an API trigger while a prior manual triage is still executing.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/826b06adc8cce78c. Report an issue: GitHub.