HKUDS/Vibe-Trading · error · ValueError

delivery.target_ref is required for configured delivery

Error message

delivery.target_ref is required for configured delivery

What it means

When delivery.mode is 'configured', the draft must include a non-empty delivery.target_ref that names a pre-configured delivery target (resolved via resolve_delivery_target into channel + target).

Source

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

        validate_timezone_shape(timezone)
    else:
        validate_timezone(timezone)
    next_run_at = now
    if timezone is not None and not is_interval_schedule(expression):
        next_run_at = next_due(expression, now, timezone)

    end_at = _parse_end_at(draft.get("end_at"))
    if end_at is not None and end_at <= now:
        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,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Include delivery.target_ref matching a configured target, e.g. {"mode":"configured","target_ref":"team-ops"}
  2. Verify the ref exists via your delivery target configuration before submitting
  3. Default the UI to require target selection when mode is configured

Example fix

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

Strategy: validation

Validate before calling

if draft.get("delivery", {}).get("mode") == "configured":
    assert str(draft["delivery"].get("target_ref") or "").strip(), "target_ref required"

Type guard

def configured_delivery_valid(d: dict) -> bool:
    return d.get("mode") != "configured" or bool(str(d.get("target_ref") or "").strip())

Try / catch

try:
    propose_create(draft)
except ValueError as e:
    if "target_ref is required" in str(e):
        draft["delivery"] = {"mode": "in_app"}  # fallback

Prevention

When it happens

Trigger: delivery={"mode":"configured"} with target_ref missing, empty, or whitespace; referencing a ref that doesn't resolve (which raises separately in resolve_delivery_target).

Common situations: Admin-configured targets not yet created; UI letting users pick 'configured' without choosing a target; ref renamed in config.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


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