{"record":{"id":"ea606350f502f3ee","repo":"ruvnet/ruflo","slug":"claim-not-found-for-issue-issueid","errorCode":null,"errorMessage":"Claim not found for issue: ${issueId}","messagePattern":"Claim not found for issue: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/claims/src/application/work-stealing-service.ts","lineNumber":211,"sourceCode":"   * monotonic across the federation. Otherwise fall back to wall clock.\n   */\n  private nowMs(): number {\n    if (this.hlc) return this.hlc.now().physicalMs;\n    return Date.now();\n  }\n\n  // ===========================================================================\n  // Mark Stealable\n  // ===========================================================================\n\n  /**\n   * Mark work as stealable with the given reason\n   */\n  async markStealable(issueId: IssueId, info: StealableInfo): Promise<void> {\n    const claim = await this.repository.findByIssueId(issueId);\n\n    if (!claim) {\n      throw new Error(`Claim not found for issue: ${issueId}`);\n    }\n\n    // Check if already stealable\n    if (claim.stealInfo) {\n      return; // Already marked\n    }\n\n    // Check grace period protection\n    if (this.isInGracePeriod(claim)) {\n      throw new Error(`Claim is still in grace period`);\n    }\n\n    // Check progress protection\n    if (this.isProtectedByProgress(claim)) {\n      throw new Error(`Claim is protected by progress (${claim.progress}%)`);\n    }\n\n    // Update claim with stealable info","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/ruvnet/ruflo/blob/6b01dc5a687b26b3e218f796de45ec51f8fa9e8c/v3/@claude-flow/claims/src/application/work-stealing-service.ts#L193-L229","documentation":"Plain Error thrown by WorkStealingService.markStealable when repository.findByIssueId(issueId) returns null. Marking an issue stealable requires a live claim to attach steal metadata to. Note the inconsistency: the sibling steal() method returns a structured StealResult error for the same condition, but markStealable throws.","triggerScenarios":"Calling markStealable on an issue that was never claimed; after the claim was released/expired; an auto-marker scanning a list that includes unclaimed or released issue ids; wrong issueId.","commonSituations":"autoMarkStealable iterating over a broad id set that contains released issues; cross-store id mismatch; stale id list.","solutions":["Confirm a claim exists (getStealable or a findByIssueId check) before marking.","Skip ids without claims in auto-mark loops rather than throwing.","Correct or prune the issueId list fed to the marker.","Re-claim the issue if it should genuinely be stealable work."],"exampleFix":"// before\nawait workStealing.markStealable(issueId, info); // throws\n\n// after\nconst claim = await repo.findByIssueId(issueId);\nif (claim) await workStealing.markStealable(issueId, info);","handlingStrategy":"validation","validationCode":"const claim = await repository.findByIssueId(issueId);\nif (!claim) return; // nothing to mark\nawait workStealing.markStealable(issueId, info);","typeGuard":null,"tryCatchPattern":"try {\n  await workStealing.markStealable(issueId, info);\n} catch (e) {\n  // plain Error; match on the known prefix\n  if (e instanceof Error && /Claim not found for issue/.test(e.message)) return;\n  throw e;\n}","preventionTips":["In auto-mark loops, skip ids without claims instead of throwing.","Keep the issueId feed pruned of released/expired issues.","Prefer the structured steal() return path where available; track the markStealable throw as a known inconsistency."],"tags":["work-stealing","precondition","plain-error"],"backgroundTag":null,"analyzedSha":"6b01dc5a687b26b3e218f796de45ec51f8fa9e8c","analyzedAt":"2026-08-12T13:20:50.148Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}