{"record":{"id":"6eef64f0bbc4e8bd","repo":"hcengineering/platform","slug":"missing-config-for-attributes-missingenv-join-6eef64","errorCode":null,"errorMessage":"Missing config for attributes: ${missingEnv.join(', ')}","messagePattern":"Missing config for attributes: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"services/backup/backup-api-pod/src/config.ts","lineNumber":39,"sourceCode":"  Bucket: string\n  Storage: string\n}\n\nconst parseNumber = (str: string | undefined): number | undefined => (str !== undefined ? Number(str) : undefined)\n\nconst config: Config = (() => {\n  const params: Partial<Config> = {\n    Port: parseNumber(process.env.PORT) ?? 4039,\n    Secret: process.env.SECRET,\n    Bucket: process.env.BUCKET_NAME,\n    AccountsUrl: process.env.ACCOUNTS_URL,\n    Storage: process.env.STORAGE\n  }\n\n  const missingEnv = (Object.keys(params) as Array<keyof Config>).filter((key) => params[key] === undefined)\n\n  if (missingEnv.length > 0) {\n    throw Error(`Missing config for attributes: ${missingEnv.join(', ')}`)\n  }\n\n  return params as Config\n})()\n\nexport default config\n","sourceCodeStart":21,"sourceCodeEnd":46,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/backup/backup-api-pod/src/config.ts#L21-L46","documentation":"The backup-api-pod config IIFE checks every Config field for undefined and throws 'Missing config for attributes' at import time. Since Port has a default (4039), the throw can only come from SECRET, BUCKET_NAME, ACCOUNTS_URL, or STORAGE being unset.","triggerScenarios":"Importing services/backup/backup-api-pod/src/config.ts without one of: SECRET, ACCOUNTS_URL, BUCKET_NAME, STORAGE. STORAGE must be a full bucket-storage config JSON string; BUCKET_NAME the target bucket.","commonSituations":"Deploying backup-api without the storage config env; missing bucket name in the deployment; secret not injected; local run without .env.","solutions":["Set the env vars named in the message: SECRET, ACCOUNTS_URL, BUCKET_NAME, STORAGE.","Provide STORAGE as a valid storage-config JSON (e.g. {\"name\":\"minio\",\"kind\":\"s3\",...}).","Verify k8s Secret/ConfigMap mounts and exact env key spelling.","Create a .env with all four vars for local development."],"exampleFix":"// before\nBUCKET_NAME=backups  # STORAGE missing\n// after\nSECRET=...\nACCOUNTS_URL=https://accounts.example.com\nBUCKET_NAME=backups\nSTORAGE={\"name\":\"minio\",\"kind\":\"s3\",\"endpoint\":\"http://minio:9000\"}","handlingStrategy":"validation","validationCode":"const missing = ['SECRET','ACCOUNTS_URL','BUCKET_NAME','STORAGE'].filter((k) => process.env[k] === undefined)\nif (missing.length > 0) throw new Error(`Missing config for attributes: ${missing.join(', ')}`)","typeGuard":"function hasEnv(key: string): boolean {\n  return process.env[key] !== undefined\n}","tryCatchPattern":"try {\n  const { default: config } = await import('./config.js')\n} catch (err) {\n  if ((err as Error).message.startsWith('Missing config for attributes:')) {\n    console.error('backup-api config error:', err.message)\n    process.exit(1)\n  }\n  throw err\n}","preventionTips":["Keep a template STORAGE JSON in .env.example and validate it parses before deploy.","Confirm BUCKET_NAME exists in your object storage before rollout.","Inject SECRET via the platform k8s Secret, not inline values.","Add a startup preflight for all four vars."],"tags":["configuration","environment-variables","backup"],"backgroundTag":"missing-env-var","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}