{"record":{"id":"7f073d76a0937f54","repo":"ruvnet/ruflo","slug":"user-token-not-found","errorCode":null,"errorMessage":"User token not found","messagePattern":"User token not found","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/server/apiToken.ts","lineNumber":6,"sourceCode":"import { config } from \"$lib/server/config\";\n\nexport function getApiToken(locals: App.Locals | undefined) {\n\tif (config.USE_USER_TOKEN === \"true\") {\n\t\tif (!locals?.token) {\n\t\t\tthrow new Error(\"User token not found\");\n\t\t}\n\t\treturn locals.token;\n\t}\n\treturn config.OPENAI_API_KEY || config.HF_TOKEN;\n}\n","sourceCodeStart":1,"sourceCodeEnd":12,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/server/apiToken.ts#L1-L12","documentation":"In task_assign's simple implementation, after the task is found and the already-assigned soft-return is skipped, the handler refuses to assign tasks whose status is terminal: 'completed', 'cancelled', or 'failed' all throw 'Cannot assign task with status: <status>'. This is a lifecycle guard — dead tasks cannot be handed to an agent. Note the asymmetry: 'pending', 'queued', 'assigned', and 'running' are all assignable, and 'failed' is terminal here but still updatable in task_update.","triggerScenarios":"Assigning a task that a worker already completed between your status check and the assign call; retrying assignment of a failed task without resetting it; re-dispatching cancelled tasks during a re-run; racing a second agent against a task that just finished.","commonSituations":"Retry logic that blindly re-assigns after timeouts when the task actually failed; UIs that show stale 'pending' state and let users assign; pipelines that do not branch on terminal status before dispatch.","solutions":["Check task_status immediately before assigning and only proceed for pending/queued/assigned/running","If the task failed and needs rework, create a new task carrying over metadata instead of resurrecting the terminal one","Catch this error specifically and treat it as a signal to refresh your local task view","Avoid fire-and-forget assignment races: mark intent in your orchestrator before calling task_assign"],"exampleFix":"// before\nawait client.callTool('task_assign', { taskId, agentId: 'worker-2' }); // task.status === 'failed' -> throws [1136]\n\n// after\nconst { status } = await client.callTool('task_status', { taskId });\nif (!['pending', 'queued', 'assigned', 'running'].includes(status)) {\n  const { task } = await client.callTool('task_create', { type: task.type, description: `retry of ${taskId}` });\n  await client.callTool('task_assign', { taskId: task.id, agentId: 'worker-2' });\n} else {\n  await client.callTool('task_assign', { taskId, agentId: 'worker-2', reassign: true });\n}","handlingStrategy":"type-guard","validationCode":"const ASSIGNABLE = new Set(['pending', 'queued', 'assigned', 'running']);\nconst { status } = await client.callTool('task_status', { taskId });\nif (!ASSIGNABLE.has(status)) throw new Error(`task ${taskId} is ${status}; create a new task instead`);","typeGuard":"type TaskStatus = 'pending' | 'queued' | 'assigned' | 'running' | 'completed' | 'failed' | 'cancelled';\nfunction isAssignableStatus(s: TaskStatus): s is 'pending' | 'queued' | 'assigned' | 'running' {\n  return s === 'pending' || s === 'queued' || s === 'assigned' || s === 'running';\n}","tryCatchPattern":"try {\n  await client.callTool('task_assign', { taskId, agentId });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Cannot assign task with status')) {\n    // terminal task — create a successor task instead of retrying\n  } else throw e;\n}","preventionTips":["Narrow status with isAssignableStatus() before every assign call","For failed-task retries, create a new task carrying the old metadata","Re-check status right before dispatch in concurrent worker pools"],"tags":["mcp","task","state-transition","assignment","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}