{"record":{"id":"f3a15df9e2b4dfd2","repo":"stablyai/orca","slug":"unconfirmed","errorCode":"unconfirmed","errorMessage":"Linear relation mutation could not be confirmed.","messagePattern":"Linear relation mutation could not be confirmed\\.","errorType":"error_code","errorClass":"LinearWriteFailure","httpStatus":null,"severity":"warning","filePath":"src/main/linear/issue-relation-mutation.ts","lineNumber":76,"sourceCode":"      { id: relationId }\n    )\n  )\n  if (raw.data?.issueRelationDelete?.success !== true) {\n    throw new LinearWriteFailure('failed', 'Linear relation removal failed')\n  }\n}\n\nasync function runRelationMutation<T>(mutation: () => Promise<T>): Promise<T> {\n  try {\n    return await mutation()\n  } catch (error) {\n    if (isAuthError(error)) {\n      throw error\n    }\n    const failure = classifyLinearWriteFailure(error)\n    if (failure.kind === 'duplicate_id') {\n      // Why: relation creates have no caller-supplied id, so a duplicate can be a concurrent add.\n      throw new LinearWriteFailure(\n        'unconfirmed',\n        'Linear relation mutation could not be confirmed.',\n        error\n      )\n    }\n    throw failure\n  }\n}\n","sourceCodeStart":58,"sourceCodeEnd":85,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/linear/issue-relation-mutation.ts#L58-L85","documentation":"Thrown by runRelationMutation when the underlying mutation fails with a duplicate_id classification. Because relation creates carry no caller-supplied id, a duplicate may actually be a successful concurrent add that Linear rejects as duplicate — so the operation cannot be confirmed either way. Encoded as LinearWriteFailure kind 'unconfirmed' with the original error as cause; isAuthError errors are rethrown unchanged.","triggerScenarios":"Two concurrent createLinearIssueRelation calls for the same issue pair (e.g. user double-submits, or two app tabs), causing Linear to return a duplicate_id error on the second. The first may have succeeded.","commonSituations":"Double-click on a 'Link issue' button. Optimistic UI re-firing after a network hiccup. Multi-window app usage.","solutions":["Treat kind 'unconfirmed' as a probable success: refetch the issue's relations to confirm whether the relation now exists.","Debounce/disable the link button until the in-flight mutation settles.","Make the create idempotent client-side by checking existing relations before re-submitting.","Do not blindly retry — that can create a third duplicate."],"exampleFix":"// before\nawait createLinearIssueRelation(client, input)\n// after\ntry { await createLinearIssueRelation(client, input) }\ncatch (e) {\n  if (e instanceof LinearWriteFailure && e.kind === 'unconfirmed') {\n    return await findRelation(input.issueId, input.relatedIssueId, input.type)\n  }\n  throw e\n}","handlingStrategy":"fallback","validationCode":"if (await findRelation(input.issueId, input.relatedIssueId, input.type)) return existingRelation","typeGuard":"function isLinearRelationUnconfirmed(e: unknown): e is LinearWriteFailure {\n  return e instanceof Error && (e as LinearWriteFailure).name === 'LinearWriteFailure' && (e as LinearWriteFailure).kind === 'unconfirmed'\n}","tryCatchPattern":"try { return await createLinearIssueRelation(client, input) }\ncatch (e) {\n  if (e instanceof LinearWriteFailure && e.kind === 'unconfirmed') return await findRelation(input.issueId, input.relatedIssueId, input.type) ?? null\n  throw e\n}","preventionTips":["Debounce the 'Link issue' button to prevent concurrent creates.","On 'unconfirmed', refetch relations to confirm rather than retrying.","Check for an existing relation before submitting a create."],"tags":["linear","relation","concurrency","duplicate","unconfirmed"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}