{"record":{"id":"a2877d88bd0e6420","repo":"paperclipai/paperclip","slug":"environment-variable-envname-is-empty-or-not-se","errorCode":null,"errorMessage":"Environment variable ${envName} is empty or not set.","messagePattern":"Environment variable (.+?) is empty or not set\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/src/commands/client/auth.ts","lineNumber":200,"sourceCode":"            handleCommandError(err);\n          }\n        }),\n    );\n  }\n}\n\nfunction parseJson(value: string): unknown {\n  return JSON.parse(value) as unknown;\n}\n\nfunction resolveChallengeToken(opts: AuthChallengeOptions): string {\n  const token = opts.token?.trim();\n  if (token) return token;\n  const envName = opts.tokenEnv?.trim();\n  if (envName) {\n    const envValue = process.env[envName]?.trim();\n    if (envValue) return envValue;\n    throw new Error(`Environment variable ${envName} is empty or not set.`);\n  }\n  throw new Error(\"Challenge secret is required. Pass --token or --token-env.\");\n}\n","sourceCodeStart":182,"sourceCodeEnd":204,"githubUrl":"https://github.com/paperclipai/paperclip/blob/120ae5428fa29bee300bcf806491cd4d965fbb7c/cli/src/commands/client/auth.ts#L182-L204","documentation":"HTTP 404 with body {\"error\":\"User secret definition not found\"} from PATCH /api/companies/:companyId/user-secret-definitions/:definitionId (secrets.ts:658). svc.updateUserSecretDefinition(companyId, definitionId, ...) returned null: no updatable definition matched the (companyId, definitionId) pair - the definition was deleted, its status was already terminal (e.g. a prior update set status 'deleted'), it belongs to another company, or it never existed. Route requires secret-definition admin (assertSecretDefinitionAdmin) and the company must match the definition.","triggerScenarios":"Patching a definition that was concurrently deleted by another admin; setting status to 'deleted' in one request and then patching it again; using a definitionId from a different company than :companyId; definition IDs stale after a reseed or after definitions were migrated.","commonSituations":"Admin UI forms kept open across a definition removal; automation that 'disables then edits' definitions in quick succession; copy/paste of definition IDs between staging and production tenants.","solutions":["Re-list the company's user secret definitions and confirm the definitionId is still present and not already deleted.","If you intended deletion, do not PATCH afterwards - deletion is terminal through this route; recreate the definition instead.","Verify :companyId matches the company the definition actually lives in.","On race with another admin, re-fetch, re-apply the surviving fields, and surface a conflict to the user instead of retrying."],"exampleFix":"// before\nawait api.patch(`/api/companies/${companyId}/user-secret-definitions/${defId}`, { status: 'active' });\n\n// after\nconst defs = await api.listUserSecretDefinitions(companyId);\nif (!defs.some((d) => d.id === defId && d.status !== 'deleted')) {\n  throw new Error(`definition ${defId} missing, cross-company, or already deleted`);\n}\nawait api.patch(`/api/companies/${companyId}/user-secret-definitions/${defId}`, { status: 'active' });","handlingStrategy":"validation","validationCode":"async function patchDefinitionSafe(api: ApiClient, companyId: string, definitionId: string, patch: unknown) {\n  const defs = await api.fetch(`/api/companies/${companyId}/user-secret-definitions`);\n  const list = await defs.json();\n  const target = (Array.isArray(list) ? list : list.items ?? []).find(\n    (d: { id: string; status?: string }) => d.id === definitionId && d.status !== 'deleted',\n  );\n  if (!target) throw new Error(`definition ${definitionId} missing or already deleted`);\n  return api.fetch(`/api/companies/${companyId}/user-secret-definitions/${definitionId}`, {\n    method: 'PATCH',\n    body: JSON.stringify(patch),\n  });\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}\nconst isDefinitionNotFound = (b: unknown): boolean =>\n  isApiErrorBody(b) && b.error === 'User secret definition not found';","tryCatchPattern":"try {\n  await api.patch(`/api/companies/${companyId}/user-secret-definitions/${defId}`, patch);\n} catch (err) {\n  if (err instanceof ApiError && err.status === 404 && isDefinitionNotFound(err.body)) {\n    await reloadDefinitions(companyId); // deleted concurrently or wrong company\n    return;\n  }\n  throw err;\n}","preventionTips":["Never PATCH a definition after setting its status to 'deleted' - recreate instead.","Reload definition lists in admin UIs right before save.","Keep definition IDs company-scoped in config; never copy between tenants.","Require secret-definition admin rights in scripts and check them before bulk edits."],"tags":["http-404","express","secrets","user-secret-definitions","company-scoping","paperclip"],"backgroundTag":"http-404-resource-not-found","analyzedSha":"120ae5428fa29bee300bcf806491cd4d965fbb7c","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}