{"record":{"id":"412a8504da73e380","repo":"paperclipai/paperclip","slug":"railway-api-not-verified","errorCode":"railway_api_not_verified","errorMessage":"Railway API access is not verified. Refresh actions or reconnect this Railway connection.","messagePattern":"Railway API access is not verified\\. Refresh actions or reconnect this Railway connection\\.","errorType":"http","errorClass":"ToolGatewayHttpError","httpStatus":422,"severity":"error","filePath":"server/src/services/tool-gateway.ts","lineNumber":5817,"sourceCode":"      },\n    };\n    const controller = new AbortController();\n    const timer = setTimeout(() => controller.abort(), ms);\n    timer.unref?.();\n    try {\n      const dispatchRemote = (target: string, init: RequestInit) =>\n        options.remoteHttpRequest\n          ? options.remoteHttpRequest(target, init)\n          : guardedRemoteHttpFetch(target, init, {\n              ...remoteHttpFetchOptions(),\n              // This call site owns a caller-set budget that can exceed the\n              // transport's default response deadline, so hand it down rather than\n              // letting the tighter default cut a legitimately slow tool short.\n              responseTimeoutMs: ms,\n            });\n      if (isRailwayEndpoint(connection.config.url) && normalizeRailwayToolName(entry.toolName).startsWith(RAILWAY_TOOL_PREFIX)) {\n        if (!isRailwayConnection(connection) || connection.config.railwayApiStatus !== \"available\") {\n          throw new ToolGatewayHttpError(422, \"Railway API access is not verified. Refresh actions or reconnect this Railway connection.\", \"railway_api_not_verified\");\n        }\n        const ssh = asRecord(connection.config.railwaySsh);\n        const sshRef = grant.credentialSecretRefs.find((ref) => ref.configPath === RAILWAY_SSH_SECRET_PATH);\n        execution.request.endpoint = RAILWAY_API_URL;\n        execution.request.protocol = entry.toolName === `${RAILWAY_TOOL_PREFIX}run-command` ? \"Railway GraphQL + SSH\" : \"Railway GraphQL\";\n        const client = createRailwayClient({\n          authorization: credentialHeaders.Authorization ?? \"\",\n          signal: controller.signal,\n          request: dispatchRemote,\n          runCommand: ssh?.grantId === grant.id && ssh?.enabled === true && sshRef\n            ? async (input) => runRailwaySshCommand({\n                ...input,\n                privateKey: await resolveGrantSecretValue(session, connection, grant, sshRef),\n                knownHosts: typeof ssh.knownHosts === \"string\" ? ssh.knownHosts : \"\",\n              })\n            : undefined,\n        });\n        const data = await client.call(entry.toolName, parameters);","sourceCodeStart":5799,"sourceCodeEnd":5835,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/tool-gateway.ts#L5799-L5835","documentation":"Before executing a Railway-namespaced tool (RAILWAY_TOOL_PREFIX, e.g. railway_run-command) whose endpoint looks like Railway, the gateway verifies the connection is a Railway connection whose railwayApiStatus is exactly \"available\". If the stored config is not a Railway connection or its API status is anything else (unverified, error, etc.), it throws this 422 ToolGatewayHttpError with reason code railway_api_not_verified. This guards against executing Railway GraphQL/SSH calls with unverified credentials.","triggerScenarios":"Invoking a railway_* tool when connection.config.railwayApiStatus !== \"available\" (e.g. the token was never verified, verification failed, or the connection is a generic MCP endpoint that merely matches isRailwayEndpoint), or the connection lacks isRailwayConnection typing.","commonSituations":"User added a Railway URL endpoint but never ran the 'refresh actions'/API-verification step; the Railway API token was revoked so re-verification flipped status away from 'available'; connection config was hand-edited and railwayApiStatus is missing.","solutions":["Run the connection's 'refresh actions' / Railway API verification flow so railwayApiStatus becomes \"available\".","Reconnect the Railway connection with a valid Railway API token, then re-verify.","Inspect connection.config.railwayApiStatus in the DB/UI; if it's 'error', fix the underlying token/permissions before retrying.","Confirm the connection was created as a Railway integration (isRailwayConnection) rather than a plain MCP endpoint with a Railway URL."],"exampleFix":"// before\nconst conn = { config: { url: \"https://railway.example.com\", railwayApiStatus: \"unverified\" } };\nawait runRailwayTool(conn, \"railway_run-command\", args); // 422\n// after\nawait refreshConnection(conn.id); // re-verifies Railway API\nconst verified = await getConnection(conn.id);\nif (verified.config.railwayApiStatus === \"available\") await runRailwayTool(verified, \"railway_run-command\", args);","handlingStrategy":"validation","validationCode":"if (conn.config?.railwayApiStatus !== \"available\") {\n  await refreshActions(conn.id); // re-verify Railway API before invoking railway_* tools\n}","typeGuard":"const isVerifiedRailway = (c) => Boolean(c && c.config?.railwayApiStatus === \"available\" && typeof c.config?.railwaySsh === \"object\");","tryCatchPattern":"try {\n  await gateway.invoke({ method: \"tools/call\", params: { name: \"railway_run-command\", arguments: args } });\n} catch (e) {\n  if (e.reasonCode === \"railway_api_not_verified\") {\n    await reconnectAndVerifyRailway(e.details?.connectionId);\n  } else throw e;\n}","preventionTips":["Run the Railway API verification (refresh actions) immediately after creating or updating a Railway connection.","Alert on railwayApiStatus leaving \"available\" (token revocation, expiry).","Ensure the connection is created through the Railway integration flow, not as a generic MCP endpoint.","Periodically re-verify long-lived Railway tokens."],"tags":["railway","verification","configuration"],"backgroundTag":"missing-required-config","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-22T11:17:16.035Z"}