{"record":{"id":"95287ac31371e962","repo":"ruvnet/ruflo","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ruflo/src/ruvocal/src/lib/server/auth.ts","lineNumber":483,"sourceCode":"\t\t\t\tconst user = await collections.users.findOne({ hfUserId: cacheHit.userId });\n\t\t\t\tif (!user) {\n\t\t\t\t\tthrow new Error(\"User not found\");\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tuser,\n\t\t\t\t\tsessionId,\n\t\t\t\t\ttoken,\n\t\t\t\t\tsecretSessionId,\n\t\t\t\t\tisAdmin: user.isAdmin || adminTokenManager.isAdmin(sessionId),\n\t\t\t\t};\n\t\t\t}\n\n\t\t\tconst response = await fetch(\"https://huggingface.co/api/whoami-v2\", {\n\t\t\t\theaders: { Authorization: `Bearer ${token}` },\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tthrow new Error(\"Unauthorized\");\n\t\t\t}\n\n\t\t\tconst data = await response.json();\n\t\t\tconst user = await collections.users.findOne({ hfUserId: data.id });\n\t\t\tif (!user) {\n\t\t\t\tthrow new Error(\"User not found\");\n\t\t\t}\n\n\t\t\tawait collections.tokenCaches.insertOne({\n\t\t\t\ttokenHash: hash,\n\t\t\t\tuserId: data.id,\n\t\t\t\tcreatedAt: new Date(),\n\t\t\t\tupdatedAt: new Date(),\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tuser,\n\t\t\t\tsessionId,","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/ruflo/src/ruvocal/src/lib/server/auth.ts#L465-L501","documentation":"After finding the task, task_update refuses to modify tasks whose status is 'completed' or 'cancelled' with 'Cannot update task with status: <status>' — priority/description/metadata changes and the like are frozen once a task reaches those terminal states. Notably 'failed' is NOT in this list, so failed tasks can still be updated (unlike in task_assign, where failed is terminal); only completion and cancellation lock the record.","triggerScenarios":"Changing priority or description of a task a worker just completed; merging metadata into a cancelled task; a UI edit racing task completion; cleanup scripts that annotate all tasks after a run, including finished ones.","commonSituations":"Post-run reporting that tries to stamp metadata onto every task; late-arriving updates from slow agents after the coordinator cancelled the task; retry tooling that updates instead of recreating.","solutions":["Gate updates on live status: only call task_update when status is not 'completed'/'cancelled' (fetch task_status first)","For finished tasks, record changes in your own store or a new linked task rather than mutating the frozen one","Re-check status immediately before the update in racy flows — completion can land between check and write","Catch this message and skip gracefully in batch annotators instead of aborting the whole batch"],"exampleFix":"// before\nawait client.callTool('task_update', { taskId, metadata: { report: 'v2' } }); // task completed -> throws [1138]\n\n// after\nconst { status } = await client.callTool('task_status', { taskId });\nif (status !== 'completed' && status !== 'cancelled') {\n  await client.callTool('task_update', { taskId, metadata: { report: 'v2' } });\n} else {\n  console.log(`task ${taskId} is ${status}; recording report externally`);\n}","handlingStrategy":"type-guard","validationCode":"const { status } = await client.callTool('task_status', { taskId });\nconst frozen = status === 'completed' || status === 'cancelled';\nif (frozen) { /* record change externally instead of task_update */ }","typeGuard":"function isUpdatableStatus(s: TaskStatus): s is 'pending' | 'queued' | 'assigned' | 'running' | 'failed' {\n  return s !== 'completed' && s !== 'cancelled'; // note: failed IS updatable here, unlike assign\n}","tryCatchPattern":"try {\n  await client.callTool('task_update', { taskId, metadata });\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Cannot update task with status')) {\n    externalAnnotations.set(taskId, metadata); // frozen — keep the record on your side\n  } else throw e;\n}","preventionTips":["Stamp metadata while tasks are live, before completion races freeze them","In batch annotators, skip (rather than abort on) completed/cancelled tasks","Remember failed tasks remain updatable — only completed/cancelled are frozen"],"tags":["mcp","task","state-transition","lifecycle","immutable"],"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"}