{"record":{"id":"b161a21a8d6773cf","repo":"paperclipai/paperclip","slug":"railway-invalid-arguments","errorCode":"railway_invalid_arguments","errorMessage":"Invalid Railway operation arguments. Use the exact IDs and limits in the action schema.","messagePattern":"Invalid Railway operation arguments\\. Use the exact IDs and limits in the action schema\\.","errorType":"error_code","errorClass":"RailwayError","httpStatus":400,"severity":"error","filePath":"server/src/services/railway.ts","lineNumber":256,"sourceCode":"\n  async function validateDeployment(args: Record<string, any>) {\n    const data = await query(RAILWAY_QUERIES.deployment, { deploymentId: args.deploymentId });\n    const d = record(data.deployment);\n    if (d.id !== args.deploymentId || d.projectId !== args.projectId || d.environmentId !== args.environmentId || d.serviceId !== args.serviceId) throw new RailwayError(\"railway_target_mismatch\", \"The deployment does not belong to the selected Railway target.\", 403);\n    return d;\n  }\n\n  return {\n    async probe(workspaceId: string) {\n      if (!id.safeParse(workspaceId).success) throw new RailwayError(\"railway_workspace_required\", \"Choose an authorized Railway workspace before checking API access.\", 400);\n      await query(RAILWAY_QUERIES.projects, { workspaceId, first: 1 });\n    },\n    async call(name: string, parameters: unknown): Promise<unknown> {\n      if (isRailwayToolBlocked(name)) throw new RailwayError(\"railway_action_blocked\", \"This Railway action cannot bind its effects to an approved target. Use redeploy, restart, or rollback for an existing deployment.\", 403);\n      const operation = name.slice(RAILWAY_TOOL_PREFIX.length) as Operation;\n      if (!name.startsWith(RAILWAY_TOOL_PREFIX) || !Object.hasOwn(schema, operation)) throw new RailwayError(\"railway_unknown_tool\", \"Unknown Railway operation.\", 400);\n      const parsed = schema[operation].safeParse(parameters);\n      if (!parsed.success) throw new RailwayError(\"railway_invalid_arguments\", \"Invalid Railway operation arguments. Use the exact IDs and limits in the action schema.\", 400);\n      const args = parsed.data as Record<string, any>;\n      let result: unknown;\n      if (operation === \"list-projects\") result = await query(RAILWAY_QUERIES.projects, args);\n      else if (operation === \"list-services\" || operation === \"list-environments\") result = await query(operation === \"list-services\" ? RAILWAY_QUERIES.services : RAILWAY_QUERIES.environments, args);\n      else {\n        const instance = await validateTarget(args);\n        const deployment = args.deploymentId ? await validateDeployment(args) : null;\n        switch (operation) {\n          case \"service-status\": result = instance; break;\n          case \"deployment-status\": result = deployment; break;\n          case \"list-deployments\": result = await query(RAILWAY_QUERIES.deployments, { input: { projectId: args.projectId, environmentId: args.environmentId, serviceId: args.serviceId }, first: args.first, after: args.after }); break;\n          case \"read-logs\": {\n            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;","sourceCodeStart":238,"sourceCodeEnd":274,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/server/src/services/railway.ts#L238-L274","documentation":"Every operation's parameters are validated with a strict Zod schema before execution; unknown keys, missing required IDs, wrong types, out-of-range paging (`first` outside 1–100), or non-UUID identifiers cause `railway_invalid_arguments` with HTTP 400. The message points callers at the action schema because the schemas are `.strict()` — extra fields are rejected, not ignored.","triggerScenarios":"Omitting required IDs (projectId/environmentId/serviceId/deploymentId); passing `first: 0` or `first: 500`; adding extra keys not in the schema; passing non-UUID strings; passing a limit outside 1–500 or a timeoutSeconds outside 1–60 for run-command; malformed timestamps not matching `z.string().datetime({offset:true})`.","commonSituations":"Hand-building arguments without consulting inputSchema; serializing optional fields as null instead of omitting them; an agent passing extra context fields it invented; pagination cursor strings longer than 512 chars.","solutions":["Validate parameters against the operation's inputSchema (exported via RAILWAY_TOOLS as JSON Schema draft-7) before calling","Pass only UUIDs obtained from prior list/status calls and omit optional fields rather than sending nulls","Clamp `first` to 1–100 and read-logs `limit` to 1–500; use `after` cursors returned by previous pages","Remove unknown keys — the schemas are strict, so any extra field fails validation"],"exampleFix":"// before\nawait client.call(\"paperclip-railway-read-logs\", { ...args, limit: 1000, debug: true });\n// after\nawait client.call(\"paperclip-railway-read-logs\", { projectId: p, environmentId: e, serviceId: s, deploymentId: d, kind: \"runtime\", limit: 500 });","handlingStrategy":"validation","validationCode":"const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\nconst ISO_OFFSET = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?(Z|[+-]\\d{2}:\\d{2})$/;\nconst clean = (o: Record<string, unknown>) => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined));\n// drop null/undefined, clamp paging: first = Math.min(100, Math.max(1, first))","typeGuard":null,"tryCatchPattern":"try {\n  return await client.call(name, params);\n} catch (e) {\n  if (isRailwayError(e) && e.code === \"railway_invalid_arguments\") {\n    const schema = operationSchemas[name]; // draft-7 JSON Schema from RAILWAY_TOOLS\n    const { valid, errors } = validate(schema, params);\n    if (!valid) throw new Error(JSON.stringify(errors)); // fail fast with field detail\n  }\n  throw e;\n}","preventionTips":["Validate against the operation's inputSchema (available in RAILWAY_TOOLS as JSON Schema) before every call","Omit optional fields entirely instead of sending null — schemas are strict","Clamp first to 1–100 and read-logs limit to 1–500","Use only UUIDs returned by previous tool calls, and ISO-8601 datetimes with explicit offset"],"tags":["railway","zod","validation","arguments"],"backgroundTag":"invalid-argument-value","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"}