HKUDS/Vibe-Trading · error · ValueError

delivery.mode must be 'in_app', 'origin', or 'configured'

Error message

delivery.mode must be 'in_app', 'origin', or 'configured'

What it means

draft.delivery.mode must be one of 'in_app', 'origin', or 'configured' (default 'in_app' when mode is absent). Any other string hits the else branch.

Source

Thrown at agent/src/scheduled_research/service.py:183

        raise ValueError("end_at must be in the future")
    if end_at is not None and next_run_at > end_at:
        raise ValueError("the first scheduled run occurs after end_at")

    mode = str(delivery_spec.get("mode") or "in_app")
    delivery_channel = delivery_target = target_ref = target_label = None
    if mode == "configured":
        target_ref = str(delivery_spec.get("target_ref") or "").strip()
        if not target_ref:
            raise ValueError("delivery.target_ref is required for configured delivery")
        target = resolve_delivery_target(target_ref)
        delivery_channel, delivery_target = target.channel, target.target
        target_label = target.label
    elif mode == "origin":
        delivery_channel, delivery_target, target_ref, target_label = _origin_target(
            session_id
        )
    elif mode != "in_app":
        raise ValueError("delivery.mode must be 'in_app', 'origin', or 'configured'")

    return ScheduledResearchJob(
        id=str(draft.get("id") or f"sr-{uuid.uuid4().hex[:12]}"),
        title=title,
        prompt=prompt,
        source_type=source_type,
        playbook_slug=playbook_slug,
        schedule=expression,
        timezone=timezone,
        next_run_at=next_run_at,
        end_at=end_at,
        status=JobStatus.PENDING,
        created_at=now,
        config=config,
        delivery_channel=delivery_channel,
        delivery_target=delivery_target,
        delivery_target_ref=target_ref,
        delivery_target_label=target_label,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Use exactly 'in_app', 'origin', or 'configured' (lowercase)
  2. For channel delivery, use mode='configured' with target_ref pointing at the channel target
  3. Omit mode to get 'in_app' by default

Example fix

// before
{"delivery": {"mode": "slack"}}
// after
{"delivery": {"mode": "configured", "target_ref": "slack-ops"}}
Defensive patterns

Strategy: validation

Validate before calling

assert draft.get("delivery", {}).get("mode", "in_app") in {"in_app", "origin", "configured"}

Type guard

def delivery_mode_valid(d: dict) -> bool:
    return str(d.get("mode") or "in_app") in {"in_app", "origin", "configured"}

Try / catch

try:
    propose_create(draft)
except ValueError as e:
    if "delivery.mode" in str(e):
        draft["delivery"]["mode"] = "in_app"; retry()

Prevention

When it happens

Trigger: delivery={"mode":"email"} or 'slack' instead of 'configured'; typos like 'inapp' or 'Origin'; modes from an older schema such as 'webhook'.

Common situations: Version drift where delivery modes were renamed; case-sensitive user input; copied examples from other tools using channel names as modes.

Related errors


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