HKUDS/Vibe-Trading · error · ProposalError

unsupported proposal operation

Error message

unsupported proposal operation

What it means

Raised by commit_proposal when the stored proposal payload's `operation` field is neither 'create' nor 'cancel'. Proposals are created with a fixed operation, so hitting this branch means the proposal file on disk was hand-edited, written by an older/newer version, or corrupted.

Source

Thrown at agent/src/scheduled_research/proposals.py:184

        runtime = scheduler_status()
        if not runtime["executable"]:
            raise ProposalError(
                "scheduled research executor is not enabled and running"
            )

        store = default_store()
        if payload["operation"] == "create":
            from src.scheduled_research.models import ScheduledResearchJob

            job = ScheduledResearchJob.from_dict(payload["internal_job"])
            store.upsert(job)
            payload["committed_job_id"] = job.id
        elif payload["operation"] == "cancel":
            if not store.delete(payload["job_id"]):
                raise ProposalError("scheduled research job no longer exists")
            payload["committed_job_id"] = payload["job_id"]
        else:
            raise ProposalError("unsupported proposal operation")
        payload["status"] = "committed"
        payload["committed_at"] = int(time.time() * 1000)
        _write(_path(proposal_id), payload)
        return public_proposal(payload)


def discard_proposal(proposal_id: str) -> dict[str, Any]:
    with _LOCK:
        payload = _read(proposal_id)
        if payload.get("status") == "pending":
            payload["status"] = "discarded"
            _write(_path(proposal_id), payload)
        return public_proposal(payload)

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Inspect the proposal file at its storage path and check payload['operation'] is exactly 'create' or 'cancel'
  2. Delete/recreate the malformed proposal through the normal propose_create/propose_cancel API
  3. If you extended operations, update the elif chain in commit_proposal to handle the new value
  4. Add a validation at proposal write time so only supported operations persist

Example fix

// before
proposal = {"operation": "update", ...}
commit_proposal(pid)
// after
proposal = {"operation": "create", ...}  # or "cancel"
commit_proposal(pid)
Defensive patterns

Strategy: validation

Validate before calling

import json
p = json.load(open(proposal_path))
assert p.get("operation") in {"create", "cancel"}, f"bad operation: {p.get('operation')!r}"

Type guard

def is_supported_operation(p: dict) -> bool:
    return isinstance(p.get("operation"), str) and p["operation"] in {"create", "cancel"}

Try / catch

try:
    commit_proposal(pid)
except ProposalError as e:
    if "unsupported proposal operation" in str(e):
        discard_or_recreate_proposal(pid)

Prevention

When it happens

Trigger: Calling commit_proposal on a proposal JSON whose operation is e.g. 'update', 'delete', or missing/typo'd; mixing proposal files between versions of the agent; tests writing proposal fixtures with invalid operation values.

Common situations: Manually crafting proposal fixtures in tests, schema drift after upgrading the scheduled-research module, or external tooling writing proposal files with unsupported operations.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/16a7021697c31548. Report an issue: GitHub.