{"record":{"id":"ec514a21c1b0af2a","repo":"immich-app/immich","slug":"failed-to-read-helmet-file-helmetfile","errorCode":null,"errorMessage":"Failed to read helmet file: ${helmetFile}","messagePattern":"Failed to read helmet file: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"server/src/repositories/config.repository.ts","lineNumber":169,"sourceCode":"  return new Set(values.length === 0 ? defaults : (values as T[]));\n};\n\nconst resolveHelmetFile = (helmetFile: 'true' | 'false' | string | undefined) => {\n  // default is off\n  if (!helmetFile || helmetFile === 'false') {\n    return;\n  }\n\n  helmetFile =\n    helmetFile === 'true'\n      ? // eslint-disable-next-line unicorn/prefer-module\n        join(__dirname, '..', '..', 'helmet.json')\n      : helmetFile;\n\n  try {\n    return JSON.parse(readFileSync(helmetFile).toString()) as HelmetOptions;\n  } catch (error) {\n    throw new Error(`Failed to read helmet file: ${helmetFile}`, { cause: error });\n  }\n};\n\nconst getEnv = (): EnvData => {\n  const parseResult = EnvSchema.safeParse(process.env);\n  if (!parseResult.success) {\n    const messages = ['Invalid environment variables: '];\n    for (const issue of parseResult.error.issues) {\n      const path = issue.path.join('.');\n      messages.push(`  - [${path}] ${issue.message}`);\n    }\n    throw new Error(messages.join('\\n'));\n  }\n  const dto = parseResult.data;\n\n  const includedWorkers = asSet(dto.IMMICH_WORKERS_INCLUDE, [ImmichWorker.Api, ImmichWorker.Microservices]);\n  const excludedWorkers = asSet(dto.IMMICH_WORKERS_EXCLUDE, []);\n  const workers = [...setDifference(includedWorkers, excludedWorkers)];","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/repositories/config.repository.ts#L151-L187","documentation":"getHelmetOptions() reads the helmet configuration file path (from env, defaulting to the packaged helmet.json when the value is 'true'). It attempts readFileSync then JSON.parse; any I/O or parse failure is rethrown as Error('Failed to read helmet file: <path>', { cause }). This runs during server config bootstrap, so a bad helmet file prevents startup.","triggerScenarios":"Setting the helmet env var to a path that does not exist, is unreadable, or contains invalid JSON; or the default packaged helmet.json is missing/corrupt in the deployment.","commonSituations":"Custom deployment that mounts a helmet config with a typo'd path; permission error reading the file; hand-edited JSON with a trailing comma; broken container image missing the bundled file.","solutions":["Check the cause on the thrown error to distinguish ENOENT (missing) from SyntaxError (bad JSON) from EACCES (permissions).","Correct the path / fix the JSON / fix file permissions, then restart.","If you do not need a custom helmet config, unset the env var so the default packaged file is used."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from 'node:fs';\nif (helmetFile && helmetFile !== 'true' && !existsSync(helmetFile)) {\n  throw new Error(`Helmet file not found: ${helmetFile}`);\n}\nif (helmetFile) JSON.parse(readFileSync(helmetFile, 'utf8')); // pre-validate JSON","typeGuard":null,"tryCatchPattern":"try {\n  startServer();\n} catch (e) {\n  if ((e as Error).message.startsWith('Failed to read helmet file')) {\n    console.error((e as Error).cause); // ENOENT vs SyntaxError\n    // fix path/JSON/perms then restart\n  } else throw e;\n}","preventionTips":["Validate the helmet file path and JSON in your deploy script before boot.","Use the default packaged helmet.json unless you specifically need a custom one.","Lint any custom JSON before deploying."],"tags":["configuration","security","helmet","startup","filesystem"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}