HKUDS/Vibe-Trading · error · ValueError

origin delivery requires the originating session

Error message

origin delivery requires the originating session

What it means

_origin_target requires a session_id because 'origin' delivery sends results back to the IM conversation that created the job. The build_job_from_draft call was made without an originating session (e.g. server-side or CLI context).

Source

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

        return None
    if isinstance(value, bool):
        raise ValueError("end_at must be RFC3339 text or epoch milliseconds")
    if isinstance(value, int):
        return value
    if not isinstance(value, str):
        raise ValueError("end_at must be RFC3339 text or epoch milliseconds")
    try:
        parsed = datetime.fromisoformat(value.strip().replace("Z", "+00:00"))
    except ValueError as exc:
        raise ValueError("end_at must be a valid RFC3339 timestamp") from exc
    if parsed.tzinfo is None:
        raise ValueError("end_at must include an explicit timezone offset")
    return int(parsed.timestamp() * 1000)


def _origin_target(session_id: str | None) -> tuple[str, str, str | None, str]:
    if not session_id:
        raise ValueError("origin delivery requires the originating session")
    host = sys.modules.get("api_server") or sys.modules.get("agent.api_server")
    service = (
        host._get_session_service()
        if host and hasattr(host, "_get_session_service")
        else None
    )
    session = service.get_session(session_id) if service else None
    config = getattr(session, "config", None) or {}
    channel = config.get("channel")
    target = config.get("channel_chat_id")
    if not isinstance(channel, str) or not isinstance(target, str):
        raise ValueError("the originating session is not an IM conversation")
    return channel, target, None, "当前会话"


def build_job_from_draft(
    draft: Mapping[str, Any],
    *,

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Pass the originating session_id when proposing the draft
  2. Or switch delivery.mode to 'in_app' or 'configured' for headless creation
  3. If creating on behalf of a user, resolve their IM session first and forward its id

Example fix

# before
build_job_from_draft(draft)  # draft.delivery.mode == 'origin'
# after
build_job_from_draft(draft, session_id=current_session_id)
Defensive patterns

Strategy: validation

Validate before calling

if draft.get("delivery", {}).get("mode") == "origin":
    assert session_id, "origin delivery requires session_id"

Type guard

def can_use_origin_delivery(draft: dict, session_id: str | None) -> bool:
    return draft.get("delivery", {}).get("mode") != "origin" or bool(session_id)

Try / catch

try:
    build_job_from_draft(draft, session_id=session_id)
except ValueError as e:
    if "originating session" in str(e):
        draft["delivery"] = {"mode": "in_app"}  # fallback

Prevention

When it happens

Trigger: Creating a scheduled research draft with delivery.mode='origin' but session_id=None — e.g. calling build_job_from_draft/propose_create from a background task, API key context, or test without a session.

Common situations: Programmatic job creation outside a chat session; refactoring a caller to drop session context; tests that don't stub a session.

Related errors


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