{"record":{"id":"6ddb42d108188238","repo":"theonedev/onedev","slug":"no-applicable-manual-transition-spec-found-for-cur-6ddb42","errorCode":null,"errorMessage":"No applicable manual transition spec found for current user (issue: {0}, from state: {1}, to state: {2})","messagePattern":"No applicable manual transition spec found for current user \\(issue: (.+?), from state: (.+?), to state: (.+?)\\)","errorType":"http","errorClass":"NotAcceptableException","httpStatus":406,"severity":"error","filePath":"server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java","lineNumber":474,"sourceCode":"\t\tvar example = new LinkedHashMap<String, Serializable>();\n\t\texample.put(\"field1\", \"value1\");\n\t\texample.put(\"field2\", new String[]{\"value1\", \"value2\"});\n\t\treturn example;\n\t}\n\n\t@Api(order=1500)\n\t@Path(\"/{issueId}/state-transitions\")\n    @POST\n    public Response transitState(@PathParam(\"issueId\") Long issueId, @NotNull @Valid StateTransitionData data) {\n\t\tIssue issue = issueService.load(issueId);\n\t\tvar subject = SecurityUtils.getSubject();\n\t\tvar user = SecurityUtils.getUser(subject);\n\t\tManualSpec transition = issue.getProject().getManualSpec(subject, issue, data.getState());\n\t\tif (transition == null) {\n\t\t\tvar message = MessageFormat.format(\n\t\t\t\t\"No applicable manual transition spec found for current user (issue: {0}, from state: {1}, to state: {2})\",\n\t\t\t\tissue.getReference().toString(), issue.getState(), data.getState());\n\t\t\tthrow new NotAcceptableException(message);\n\t\t}\n    \t\n\t\tvar fieldValues = FieldUtils.getFieldValues(subject, issue.getProject(), data.getFields());\n\t\tissueChangeService.changeState(user, issue, data.getState(), fieldValues, \n\t\t\t\ttransition.getPromptFields(), transition.getRemoveFields(), data.getComment());\n\t\treturn Response.ok().build();\n    }\n\n\t@Api(order=1550, example = \"/~downloads/projects/1/attachments/6a5a1a20-c8c0-44a5-a1bb-8a3d2a830094/attachment.txt\", \n\t\t\tdescription = \"Upload attachment to issue and get attachment url via response. This url can then be used in issue description or comment\")\n\t@Path(\"/{issueId}/attachments/{preferredAttachmentName}\")\n    @POST\n\t@Consumes(MediaType.APPLICATION_OCTET_STREAM)\n    public String uploadAttachment(@PathParam(\"issueId\") Long issueId, @PathParam(\"preferredAttachmentName\") String preferredAttachmentName, InputStream input) {\n\t\tIssue issue = issueService.load(issueId);\n    \tif (!SecurityUtils.canModifyIssue(issue))\n\t\t\tthrow new UnauthorizedException();\n\t\t\t","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/theonedev/onedev/blob/d44925c47c37992c828ea673a5f9620539bc3ff2/server-core/src/main/java/io/onedev/server/rest/resource/IssueResource.java#L456-L492","documentation":"State transitions via the REST API must match a manual transition spec defined in the project's issue workflow that applies to the current user, current state, and target state. issue.getProject().getManualSpec(subject, issue, toState) returning null yields NotAcceptableException (HTTP 406) with issue, from-state and to-state details.","triggerScenarios":"POST to /api/issues/{issueId}/transit (transitState) with data.getState() equal to a state for which no applicable manual transition spec exists for the user — e.g., target state only reachable via other transitions, spec restricted by role/condition, or state name mismatch.","commonSituations":"Automations skipping multi-step workflows (attempting direct jump to a closed state); workflow customized so transitions require authorization the API user lacks; renamed states causing exact-name mismatches.","solutions":["Add/adjust a manual transition spec in Project -> Issue Setting -> Workflow for the from-state to the target state applicable to the user.","Transition through intermediate states that have defined specs, in order.","Verify the exact target state name matches the workflow state.","Ensure the API user satisfies the transition spec's authorization/condition."],"exampleFix":"// before\nPOST /api/issues/12/transit {\"state\":\"Closed\"}  // no spec Open->Closed\n// after: define a manual transition Open -> Closed in the workflow, or\nPOST /api/issues/12/transit {\"state\":\"In Progress\"}  // then Closed","handlingStrategy":"validation","validationCode":"const workflow = await getIssueWorkflow(projectPath);\nconst spec = workflow.states[state]\n  ?.transitions?.find(t => t.toState === targetState && t.type === 'MANUAL' && appliesToUser(t, me));\nif (!spec) throw new Error(`No manual transition ${state} -> ${targetState} for current user; check workflow`);","typeGuard":null,"tryCatchPattern":"try {\n  await api.transitIssueState(issueId, payload);\n} catch (e) {\n  if (e.status === 406 && /No applicable manual transition spec/.test(e.message))\n    log.error(`Workflow has no manual transition to ${payload.state}; adjust workflow or path`);\n  else throw e;\n}","preventionTips":["Mirror the project's workflow graph in automation and only traverse defined manual transitions.","Use exact state names as defined in the workflow spec.","After workflow edits, regenerate the transition map used by scripts.","Account for role/condition restrictions in transition specs."],"tags":["rest-api","workflow","state-transition","validation"],"backgroundTag":"invalid-state-transition","analyzedSha":"d44925c47c37992c828ea673a5f9620539bc3ff2","analyzedAt":"2026-09-06T07:18:27.995Z","contentChangedAt":"2026-09-06T07:18:27.995Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}