odysseus-dev/odysseus · error · Error
Failed to stop task (${res.status})
Error message
Failed to stop task (${res.status}) What it means
Thrown by the tasks UI when POST /api/tasks/{id}/stop returns a non-2xx status. As with trigger, the client prefers the backend's JSON `detail` field; this literal is the fallback message. There is no special-casing for stop, so a 409 (not running) surfaces as the backend detail if present, otherwise the generic status message.
Source
Thrown at static/js/tasks.js:178
if (data && data.detail) msg = data.detail;
} catch (_) {}
if (res.status === 409) msg = 'Task is already running';
throw new Error(msg);
}
}
async function _stopTask(id) {
const res = await fetch(`${API_BASE}/api/tasks/${id}/stop`, {
method: 'POST',
credentials: 'same-origin',
});
if (!res.ok) {
let msg = `Failed to stop task (${res.status})`;
try {
const data = await res.json();
if (data && data.detail) msg = data.detail;
} catch (_) {}
throw new Error(msg);
}
}
async function _fetchRuns(taskId, limit = 10) {
const res = await fetch(`${API_BASE}/api/tasks/${taskId}/runs?limit=${limit}`, {
credentials: 'same-origin',
});
if (!res.ok) return [];
const data = await res.json();
return data.runs || [];
}
let _outputTargets = null;
async function _fetchOutputTargets() {
if (_outputTargets) return _outputTargets;
try {
const res = await fetch(`${API_BASE}/api/tasks/meta/output-targets`, { credentials: 'same-origin' });
const data = await res.json();View on GitHub (pinned to f9235ebbf1)
Solutions
- Check the HTTP status: 404 = task gone (refresh list), 401/403 = re-authenticate, 409/400 = run already finished (harmless, refresh the run state)
- Refresh the task's status via GET /api/tasks before showing the stop control
- Inspect the server log if status is 500
Example fix
// before
if (!res.ok) {
let msg = `Failed to stop task (${res.status})`;
...
// after — mirror the trigger path and humanize 409
if (!res.ok) {
let msg = `Failed to stop task (${res.status})`;
try { const data = await res.json(); if (data && data.detail) msg = data.detail; } catch (_) {}
if (res.status === 409) msg = 'Task is not running'; Defensive patterns
Strategy: try-catch
Validate before calling
const task = _tasks.find(t => t.id === id);
if (!task || task.status !== 'active') { showToast('Task is not running'); return; } Try / catch
try { await _stopTask(id); } catch (e) { if (/\(409\)/.test(e.message) || /not running/i.test(e.message)) return; uiModule?.showError(e.message); } Prevention
- Only enable the Stop control when the task status is 'active'
- Re-fetch status after run completion events
- Ignore 'not running' races instead of erroring
When it happens
Trigger: Clicking Stop on a task that is not currently running, on a task id that no longer exists (404), with an expired session (401/403), or when the stop endpoint returns a non-JSON body so data.detail cannot be read.
Common situations: Stop button clicked from a stale UI where the run already finished; race between the run completing and the user clicking stop; auth cookie expired.
Related errors
- Failed to trigger task (${res.status})
- Failed to revert task
- HTTP ${res.status}
- Failed to save note
- Failed to create task
AI-assisted analysis of odysseus-dev/odysseus@f9235ebbf1 (2026-08-14).
Data as JSON: /api/errors/8b08538eb09d6ded.
Report an issue: GitHub.