{"record":{"id":"5df2a753ec777987","repo":"ruvnet/ruflo","slug":"issue-input-issueid-is-not-stealable-or-not-cla","errorCode":null,"errorMessage":"Issue ${input.issueId} is not stealable or not claimed","messagePattern":"Issue (.+?) is not stealable or not claimed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/claims/src/api/mcp-tools.ts","lineNumber":947,"sourceCode":"\n      // Update issue\n      const issue = issueStore.get(input.issueId);\n      if (issue) {\n        issue.claimedBy = input.stealerId;\n      }\n\n      return {\n        stolen: true,\n        issueId: input.issueId,\n        newClaimId,\n        previousClaimant,\n        contestWindowMs: 300000, // 5 minutes\n        stolenAt,\n      };\n    }\n  }\n\n  throw new Error(`Issue ${input.issueId} is not stealable or not claimed`);\n}\n\n/**\n * Get stealable issues\n */\nasync function handleIssueGetStealable(\n  input: z.infer<typeof issueGetStealableSchema>,\n  context?: ToolContext\n): Promise<{\n  issues: Array<{\n    issueId: string;\n    title: string;\n    priority: IssuePriority;\n    currentClaimant: string;\n    stealableReason?: string;\n  }>;\n  total: number;\n}> {","sourceCodeStart":929,"sourceCodeEnd":965,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/claims/src/api/mcp-tools.ts#L929-L965","documentation":"Thrown by the steal handler in @claude-flow/claims when the target issue cannot be stolen: the handler requires an existing claim that is currently claimed AND already flagged stealable (claim.stealable === true). If the claim is missing, released, or the owner never marked it stealable, the steal is rejected with this combined message.","triggerScenarios":"Calling issue_steal directly on a normally-claimed issue (owner never ran mark-stealable); stealing after the claim was released or after a restart cleared the store; stealing twice — the second call finds the first steal already transferred ownership so the old claim no longer qualifies; using the wrong issueId.","commonSituations":"Eager workers trying to take over blocked tasks without the courtesy mark-stealable step; retry logic duplicating a steal that already succeeded; races between steal and release.","solutions":["Have the owner mark the claim stealable first (mark-stealable with the owner's claimantId), then steal","Confirm current state before stealing: claim exists, claimed by someone, stealable === true, and you are not already the owner","Handle idempotency: if the steal already succeeded, treat 'not stealable or not claimed' as success when you now hold the claim"],"exampleFix":"// before\nawait stealTool({ issueId, claimantId: 'agent-2', claimantType: 'agent' });\n\n// after\nconst claim = await getClaimTool({ issueId });\nif (!claim.stealable && claim.claimantId !== 'agent-2') {\n  await markStealableTool({ issueId, claimantId: claim.claimantId, reason: 'handoff' });\n}\nawait stealTool({ issueId, claimantId: 'agent-2', claimantType: 'agent' });","handlingStrategy":"validation","validationCode":"const claim = await getClaimTool({ issueId });\nif (!claim || !claim.claimedBy || claim.claimedBy === claimantId) {\n  return { stolen: false, reason: 'nothing to steal' };\n}\nif (!claim.stealable) {\n  await markStealableTool({ issueId, claimantId: claim.claimantId, reason: 'unblocking' });\n}\nawait stealTool({ issueId, claimantId, claimantType });","typeGuard":null,"tryCatchPattern":"try { await stealTool(input); } catch (e) { if (e instanceof Error && e.message.includes('not stealable or not claimed')) { const c = await getClaimTool({ issueId: input.issueId }); if (c.claimantId === input.claimantId) return { stolen: true }; /* already ours */ throw e; } throw e; }","preventionTips":["Follow the two-step protocol: owner marks stealable, then stealer steals","Make steal idempotent by re-checking current ownership afterwards","Verify claim.stealable === true before calling steal"],"tags":["claims","mcp-tools","work-stealing","precondition"],"backgroundTag":"precondition-failed","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"}