odysseus-dev/odysseus · error · HTTPException

Cannot chain to another user's task

Error message

Cannot chain to another user's task

What it means

Ownership guard on task chaining: the chained target task exists but belongs to a different owner than the requesting user, so linking would let one user trigger another's tasks. Returned as HTTP 403.

Source

Thrown at routes/task_routes.py:527

        task_id = str(uuid.uuid4())
        db = SessionLocal()
        try:
            then_task_id = _validate_then_task_id(db, req.then_task_id, user)
            notifications_enabled = (
                False if req.task_type == "action" and req.notifications_enabled is None
                else bool(req.notifications_enabled) if req.notifications_enabled is not None
                else True
            )
            # Validate chained task belongs to same owner
            if req.then_task_id:
                chain_target = db.query(ScheduledTask).filter(
                    ScheduledTask.id == req.then_task_id
                ).first()
                if not chain_target:
                    raise HTTPException(400, "Chained task not found")
                if chain_target.owner != user:
                    raise HTTPException(403, "Cannot chain to another user's task")
            task = ScheduledTask(
                id=task_id,
                owner=user,
                name=name,
                prompt=req.prompt,
                task_type=req.task_type,
                action=req.action,
                schedule=req.schedule,
                scheduled_time=req.scheduled_time,
                scheduled_day=req.scheduled_day,
                scheduled_date=sched_date,
                cron_expression=req.cron_expression,
                trigger_type=req.trigger_type,
                trigger_event=req.trigger_event,
                trigger_count=req.trigger_count,
                trigger_counter=0,
                next_run=next_run,
                status="active" if (req.trigger_type in ("event", "webhook") or next_run) else "completed",

View on GitHub (pinned to f9235ebbf1)

Solutions

  1. Chain only to tasks owned by the same account.
  2. Restrict the client's chain-target picker to the current user's task list (GET /api/tasks already scopes by owner).
  3. If cross-user chaining is a legitimate feature request, it needs an explicit server-side grant mechanism, not removal of this check.

Example fix

// before
const target = allTasks.find(t => t.name === 'Admin Cleanup'); // may be another user's

// after
const myTasks = await api.listTasks(); // owner-scoped
const target = myTasks.find(t => t.name === 'Cleanup');
if (!target) throw new Error('Pick one of your own tasks');
Defensive patterns

Strategy: validation

Validate before calling

async function canChainTo(thenTaskId) {
  const res = await fetch(`/api/tasks/${encodeURIComponent(thenTaskId)}`);
  if (res.status === 403) return false; // not yours
  return res.ok;
}

Try / catch

try { await api.createTask(p); }
catch (e) {
  if (e.status === 403 && /another user/.test(e.message)) { showOwnTasksOnly(); return; }
  throw e;
}

Prevention

When it happens

Trigger: POST/PUT a task with then_task_id equal to an id owned by another account on a multi-owner instance. The earlier helper only applies the owner filter when user is set, so this explicit owner != user comparison is the authoritative cross-owner block.

Common situations: Multi-user deployment where a user discovers/guesses another's task id; admin-created tasks being chained by regular users; shared ids in documentation or exported configs; migrating tasks between accounts leaving stale chain references.

Related errors


AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14). Data as JSON: /api/errors/1daca2d0aed9fbbe. Report an issue: GitHub.