{"record":{"id":"b7e2774de317291b","repo":"paperclipai/paperclip","slug":"payload-must-be-a-json-object","errorCode":null,"errorMessage":"--payload must be a JSON object","messagePattern":"--payload must be a JSON object","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/agent.ts","lineNumber":873,"sourceCode":"              }\n            }\n          }\n          console.log(\"\");\n          console.log(\"# Run this in your shell before launching codex/claude:\");\n          console.log(exportsText);\n        } catch (err) {\n          handleCommandError(err);\n        }\n      }),\n    { includeCompany: false },\n  );\n}\n\nfunction parseJsonObject(value: string | undefined): Record<string, unknown> | undefined {\n  if (value === undefined) return undefined;\n  const parsed = JSON.parse(value) as unknown;\n  if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n    throw new Error(\"--payload must be a JSON object\");\n  }\n  return parsed as Record<string, unknown>;\n}\n\nfunction parseJson(value: string): unknown {\n  return JSON.parse(value) as unknown;\n}\n\nfunction parseCsv(value: string | undefined): string[] {\n  if (!value) return [];\n  return value.split(\",\").map((part) => part.trim()).filter(Boolean);\n}\n","sourceCodeStart":855,"sourceCodeEnd":886,"githubUrl":"https://github.com/paperclipai/paperclip/blob/a7e689b3c35347b529cb9f54c9b9a8575a3dcab6/cli/src/commands/client/agent.ts#L855-L886","documentation":"HTTP 404 with body {\"error\":\"Routine not found\"} from POST /api/routines/:id/run (manually trigger a routine run). assertCanManageExistingRoutine (routines.ts:108-118) resolves the routine; null (missing or cross-company) maps to this 404 before the assertBoardCanAssignTasks permission gate and svc.runRoutine execute. So a manual run request failed to even locate an actionable routine for this actor.","triggerScenarios":"Manually running a deleted routine; an agent key from another company attempting to run a routine; run requests against a stale routine ID after DB reseed; a 'Run now' button in a UI holding a routine that was removed moments earlier.","commonSituations":"Ops runbooks with hardcoded routine IDs breaking after routine re-creation; schedulers or chat commands firing runs for routines retired between configuration and invocation.","solutions":["Preflight GET /api/routines/:id; only call /run when it returns 200.","Confirm the actor may run routines in that company (board or tasks:assign permission) - otherwise expect 403 after the existence gate.","For scheduled/manual invocations, resolve the routine by a stable reference (e.g. name lookup from GET /api/routines) instead of a stored ID.","If the routine was deleted intentionally, remove the schedule/automation that still references it."],"exampleFix":"// before\nawait api.post(`/api/routines/${routineId}/run`, { input });\n\n// after\nconst routine = await api.get(`/api/routines/${routineId}`);\nif (!routine) {\n  throw new Error(`routine ${routineId} not found; resolve by name or refresh the runbook`);\n}\nawait api.post(`/api/routines/${routineId}/run`, { input });","handlingStrategy":"validation","validationCode":"async function runRoutineSafe(api: ApiClient, routineId: string, input: unknown) {\n  const res = await api.fetch(`/api/routines/${routineId}`);\n  if (res.status === 404) {\n    throw new Error(`routine ${routineId} deleted or cross-company; cannot run`);\n  }\n  return api.fetch(`/api/routines/${routineId}/run`, { method: 'POST', body: JSON.stringify(input ?? {}) });\n}","typeGuard":"function isApiErrorBody(body: unknown): body is { error: string } {\n  return typeof body === 'object' && body !== null &&\n    typeof (body as Record<string, unknown>).error === 'string';\n}","tryCatchPattern":"try {\n  const run = await api.post(`/api/routines/${id}/run`, input);\n} catch (err) {\n  if (err instanceof ApiError && err.status === 404 && err.body?.error === 'Routine not found') {\n    throw new RoutineGoneError(id); // caller re-resolves by name/listing\n  }\n  throw err;\n}","preventionTips":["Resolve routines by a stable property (name/slug from the listing) for scheduled runs, not stored IDs.","Require a fresh existence check in 'Run now' handlers right before firing.","Remove schedules automatically when their target routine 404s.","Provision running actors with tasks:assign permission to avoid post-404 403 surprises."],"tags":["http-404","express","routines","run","company-scoping","paperclip"],"backgroundTag":"http-404-resource-not-found","analyzedSha":"a7e689b3c35347b529cb9f54c9b9a8575a3dcab6","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}