{"record":{"id":"6b4cc343f6fd9866","repo":"paperclipai/paperclip","slug":"railway-deployment-ineligible","errorCode":"railway_deployment_ineligible","errorMessage":"Railway does not allow this deployment to be redeployed.","messagePattern":"Railway does not allow this deployment to be redeployed\\.","errorType":"error_code","errorClass":"RailwayError","httpStatus":409,"severity":"error","filePath":"server/src/services/railway.ts","lineNumber":287,"sourceCode":"            if (args.startDate && args.endDate && Date.parse(args.startDate) > Date.parse(args.endDate)) throw new RailwayError(\"railway_invalid_arguments\", \"Log start time must precede end time.\", 400);\n            const data = await query(args.kind === \"build\" ? RAILWAY_QUERIES.buildLogs : RAILWAY_QUERIES.runtimeLogs, { deploymentId: args.deploymentId, limit: args.limit, startDate: args.startDate, endDate: args.endDate, filter: args.filter });\n            const lines = data[args.kind === \"build\" ? \"buildLogs\" : \"deploymentLogs\"];\n            if (!Array.isArray(lines)) throw new RailwayError(\"railway_invalid_response\", \"Railway returned invalid log data.\");\n            let bytes = 0;\n            let messageTruncated = false;\n            const bounded = [];\n            for (const line of lines.slice(0, args.limit)) {\n              const message = String(line.message ?? \"\");\n              if (message.length > 8192) messageTruncated = true;\n              const safe = redact({ timestamp: line.timestamp, severity: line.severity, message: message.slice(0, 8192) });\n              bytes += Buffer.byteLength(JSON.stringify(safe));\n              if (bytes > 64 * 1024) break;\n              bounded.push(safe);\n            }\n            result = { deploymentId: args.deploymentId, kind: args.kind, lines: bounded, truncated: messageTruncated || bounded.length < lines.length, limitReached: lines.length >= args.limit }; break;\n          }\n          case \"redeploy\":\n            if (!deployment?.canRedeploy) throw new RailwayError(\"railway_deployment_ineligible\", \"Railway does not allow this deployment to be redeployed.\", 409);\n            result = await query(RAILWAY_QUERIES.redeploy, { deploymentId: args.deploymentId });\n            if (!id.safeParse(record(record(result).deploymentRedeploy).id).success) throw new RailwayError(\"railway_operation_unconfirmed\", \"Railway did not confirm a resulting deployment. Inspect deployment status before retrying.\");\n            break;\n          case \"restart\":\n            result = await query(RAILWAY_QUERIES.restart, { deploymentId: args.deploymentId });\n            if (record(result).deploymentRestart !== true) throw new RailwayError(\"railway_operation_unconfirmed\", \"Railway did not confirm the restart. Inspect deployment status before retrying.\");\n            result = { ...record(result), targetDeploymentId: args.deploymentId };\n            break;\n          case \"rollback\":\n            if (!deployment?.canRollback) throw new RailwayError(\"railway_deployment_ineligible\", \"Railway does not allow rollback to this deployment.\", 409);\n            result = await query(RAILWAY_QUERIES.rollback, { deploymentId: args.deploymentId });\n            if (record(result).deploymentRollback !== true) throw new RailwayError(\"railway_operation_unconfirmed\", \"Railway did not confirm the rollback. Inspect deployment status before retrying.\");\n            result = { ...record(result), targetDeploymentId: args.deploymentId };\n            break;\n          case \"run-command\":\n            if (!Array.isArray(deployment?.instances) || !deployment.instances.some((entry: { id: string }) => entry.id === args.deploymentInstanceId) || deployment.status !== \"SUCCESS\") throw new RailwayError(\"railway_target_mismatch\", \"The container instance is not part of the selected running deployment.\", 403);\n            if (!options.runCommand) throw new RailwayError(\"railway_ssh_setup_required\", \"Configure Container access on this Railway connection before running commands.\", 422);\n            result = await options.runCommand({ deploymentInstanceId: args.deploymentInstanceId, command: args.command, timeoutSeconds: args.timeoutSeconds, signal: options.signal }); break;","sourceCodeStart":269,"sourceCodeEnd":305,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/railway.ts#L269-L305","documentation":"The `redeploy` Railway operation throws `railway_deployment_ineligible` (HTTP 409) when the target deployment's `canRedeploy` flag is false or missing, as fetched via `validateDeployment` against the Railway GraphQL API. Railway only permits redeploying deployments that are eligible (typically active/recent deployments on services with redeploy enabled); crashed, removed, or very old builds are ineligible. The check runs before the mutation so no partial state is created.","triggerScenarios":"Calling the `railway_redeploy` tool with a `deploymentId` whose `deployment.canRedeploy` field returned false from the RAILWAY_QUERIES.deployment lookup — e.g. redeploying an already-crashed deployment, a deployment for a service whose latest snapshot no longer exists, or an ancient deployment past Railway's redeploy window.","commonSituations":"Agents or scripts caching an old deploymentId and replaying it days later; attempting to redeploy after a service's settings changed (e.g. image-based or template services that don't support redeploy); picking a superseded deployment from `list-deployments` instead of the latest; redeploying deployments attached to deleted environments or branches.","solutions":["Fetch current deployments via `railway_list-deployments` and redeploy the latest eligible deployment instead of the stale one.","Run `railway_deployment-status` for the deploymentId and verify `canRedeploy: true` before invoking redeploy.","If the deployment is permanently ineligible, trigger a new deployment (e.g. push to the connected branch) rather than redeploying.","Confirm the service type supports redeploy (some image/template-based services don't) and update service settings if needed."],"exampleFix":"// before\nawait railwayCall(\"railway_redeploy\", { projectId, environmentId, serviceId, deploymentId: staleId });\n// after\nconst d = await railwayCall(\"railway_deployment-status\", { projectId, environmentId, serviceId, deploymentId });\nif (!d.canRedeploy) {\n  const list = await railwayCall(\"railway_list-deployments\", { projectId, environmentId, serviceId, first: 1 });\n  deploymentId = list.deployments.edges[0].node.id;\n}\nawait railwayCall(\"railway_redeploy\", { projectId, environmentId, serviceId, deploymentId });","handlingStrategy":"validation","validationCode":"const d = await railwayCall(\"railway_deployment-status\", { projectId, environmentId, serviceId, deploymentId });\nif (!d || d.canRedeploy !== true) {\n  throw new Error(`Deployment ${deploymentId} is not redeployable; select a recent eligible deployment`);\n}","typeGuard":"function canRedeploy(d) {\n  return typeof d === \"object\" && d !== null && d.canRedeploy === true && typeof d.id === \"string\";\n}","tryCatchPattern":"try {\n  await railwayCall(\"railway_redeploy\", args);\n} catch (e) {\n  if (e?.code === \"railway_deployment_ineligible\") {\n    // fall back to latest eligible deployment\n    const list = await railwayCall(\"railway_list-deployments\", { projectId, environmentId, serviceId, first: 1 });\n    await railwayCall(\"railway_redeploy\", { ...args, deploymentId: list.deployments.edges[0].node.id });\n  } else throw e;\n}","preventionTips":["Always check `canRedeploy` via deployment-status before issuing redeploy.","Resolve deployment IDs fresh from list-deployments rather than caching them.","Treat redeploy as branch-push alternative only when the deployment is recent and successful.","Watch for 409 status on this code and route to target-selection logic."],"tags":["railway","deployment","precondition-failed","conflict"],"backgroundTag":"invalid-state-transition","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}