{"record":{"id":"b0d683c615a2e5db","repo":"mastra-ai/mastra","slug":"linear-did-not-accept-the-issue-update","errorCode":null,"errorMessage":"Linear did not accept the issue update.","messagePattern":"Linear did not accept the issue update\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mastracode/factory/src/integrations/linear/integration.ts","lineNumber":719,"sourceCode":"      const wantedType = input.state.stateType;\n      targetState = states.find(state => state.type === wantedType) ?? null;\n    } else {\n      const wanted = input.state.name.toLowerCase();\n      targetState = states.find(state => state.name.toLowerCase() === wanted) ?? null;\n    }\n    if (!targetState) return null;\n    if (targetState.name === issue.state) {\n      return linearIssueToIntakeIssue(issue);\n    }\n    const data = await linearGraphql<{ issueUpdate: { success: boolean } }>(\n      accessToken,\n      `mutation UpdateIssueState($id: String!, $stateId: String!) {\n        issueUpdate(id: $id, input: { stateId: $stateId }) { success }\n      }`,\n      { id: issue.id, stateId: targetState.id },\n    );\n    if (!data.issueUpdate.success) {\n      throw new Error('Linear did not accept the issue update.');\n    }\n    const fresh = await this.fetchIssueDetail(accessToken, issue.id);\n    if (!fresh) return null;\n    return linearIssueToIntakeIssue(fresh);\n  }\n\n  async #listTeamWorkflowStates(\n    accessToken: string,\n    teamKey: string,\n  ): Promise<Array<{ id: string; name: string; type: string }>> {\n    const data = await linearGraphql<{\n      team: { states: { nodes: Array<{ id: string; name: string; type: string }> } } | null;\n    }>(\n      accessToken,\n      `query TeamStates($key: String!) {\n        team(id: $key) { states(first: 100) { nodes { id name type } } }\n      }`,\n      { key: teamKey },","sourceCodeStart":701,"sourceCodeEnd":737,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/mastracode/factory/src/integrations/linear/integration.ts#L701-L737","documentation":"LinearIntegration throws this when Linear's GraphQL `issueUpdate` mutation completes but reports `success: false`, meaning the API rejected the state change (target state id, permissions, or issue state) even though the HTTP request itself succeeded. The mutation returns a payload without throwing, so the integration explicitly converts a falsy `success` into a thrown error. It indicates the issue's status was NOT changed.","triggerScenarios":"Calling any LinearIntegration method that moves an issue between states (e.g. marking an issue in-progress/done) where Linear's `issueUpdate` mutation responds with `success: false` — typically because `stateId` does not belong to the issue's team, the state was deleted/renamed, the OAuth token lacks `write` scope for issues, or the issue was deleted/archived between lookup and update.","commonSituations":"The workflow state name lookup resolved a stale or wrong-team state id; a Linear workspace admin changed the team's workflow states; the bot token's scope was reduced; the issue was canceled or migrated while a task was running; concurrent automation already moved the issue to a state that blocks this transition.","solutions":["Re-fetch the issue's team workflow states via Linear's API and retry the update with a freshly resolved `stateId` for the target state name.","Verify the OAuth token used has the required `write` scope (issues) in Linear developer settings.","Check the issue still exists and is not archived/canceled (`issueQuery` before update).","Log the raw GraphQL response for `issueUpdate.userErrors`/errors to get Linear's specific rejection reason.","Retry after a short backoff if the failure followed a concurrent state change."],"exampleFix":"// before\nif (!data.issueUpdate.success) {\n  throw new Error('Linear did not accept the issue update.');\n}\n// after\nif (!data.issueUpdate.success) {\n  const states = await this.fetchTeamWorkflowStates(accessToken, teamId);\n  const refreshed = states.find(s => s.id === targetState.id) ?? states.find(s => s.name === targetState.name);\n  if (!refreshed) throw new Error(`State \"${targetState.name}\" no longer exists in Linear team ${teamId}.`);\n  await this.updateIssueState(accessToken, issue, refreshed);\n}","handlingStrategy":"retry","validationCode":"const states = await getTeamWorkflowStates(accessToken, issue.teamId);\nconst target = states.find(s => s.id === targetState.id && s.type === 'started');\nif (!target) throw new Error(`State ${targetState.id} not found for team ${issue.teamId}; refresh state ids before updating.`);","typeGuard":"function isSuccessfulUpdate(r: { issueUpdate?: { success?: boolean } | null }): r is { issueUpdate: { success: true } } {\n  return r?.issueUpdate?.success === true;\n}","tryCatchPattern":"try {\n  await integration.updateIssueState(issue, targetState);\n} catch (e) {\n  if (e.message === 'Linear did not accept the issue update.') {\n    await sleep(1000);\n    const fresh = await integration.fetchIssue(issue.id);\n    if (fresh) await integration.updateIssueState(fresh, targetState); // retry with fresh issue/state\n  } else throw e;\n}","preventionTips":["Always resolve the target state id from a fresh workflow-state query for the issue's team, never from cache.","Check the OAuth token has issue write scope when connecting the integration.","Re-fetch the issue right before updating to catch archived/deleted issues.","Log Linear's raw GraphQL errors alongside this message for diagnosis.","Debounce concurrent automations that move the same issue."],"tags":["linear","graphql","api-rejected","state-update"],"backgroundTag":"linear-api-rejected-mutation","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}