{"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":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/repositories/config.repository.ts","lineNumber":165,"sourceCode":"const TELEMETRY_TYPES = new Set(Object.values(ImmichTelemetry));\n\nconst asSet = <T>(value: string | undefined, defaults: T[]) => {\n  const values = (value || '').replaceAll(/\\s/g, '').split(',').filter(Boolean);\n  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 = helmetFile === 'true' ? join(import.meta.dirname, '..', '..', 'helmet.json') : 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":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/repositories/config.repository.ts#L147-L183","documentation":"This error is thrown when the server cannot read the helmet.json file (helmet/CSP security headers config). resolveHelmetFile resolves IMMICH_HELMET_FILE to a path (defaulting to <buildDir>/helmet.json when set to 'true'), then reads and JSON.parses it synchronously; if readFileSync or JSON.parse fails, the path resolution error is wrapped and rethrown with the offending path in the message.","triggerScenarios":"process.env.IMMICH_HELMET_FILE is set to a path that does not exist, is unreadable due to permissions, is a directory, or contains invalid JSON; or helmetFile is 'true' but the resolved join(import.meta.dirname,'..','..','helmet.json') file is absent from the deployment (e.g. trimmed container image or running from source outside the expected layout).","commonSituations":"Docker images built without helmet.json copied into /build; running the server via tsx/node from a directory that breaks the relative ../.. resolution; mounting a custom helmet.json with a wrong container path; invalid JSON hand-edited into the file.","solutions":["Verify the file exists and is readable at the resolved path: ls -l <resolved-path> and check JSON validity with node -e 'JSON.parse(require(\"fs\").readFileSync(process.argv[1]))' <path>","If IMMICH_HELMET_FILE=true, ensure helmet.json is present at <build folder>/helmet.json (check your build/Dockerfile copies it)","Point IMMICH_HELMET_FILE at an explicit absolute path to a valid helmet.json instead of relying on the default resolution","Restore a minimal valid helmet.json (e.g. {}) if the file was corrupted"],"exampleFix":"// before\ndocker run immich-server  # IMMICH_HELMET_FILE=true, helmet.json missing in image\n// after\n# in Dockerfile\ncopy ./server/helmet.json /build/helmet.json\n# or explicitly\ne docker run -e IMMICH_HELMET_FILE=/config/helmet.json -v ./helmet.json:/config/helmet.json ...","handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from 'node:fs';\nconst helmetFile = process.env.IMMICH_HELMET_FILE === 'true'\n  ? new URL('../../helmet.json', import.meta.url).pathname\n  : process.env.IMMICH_HELMET_FILE;\nif (helmetFile && !existsSync(helmetFile)) throw new Error(`helmet file missing: ${helmetFile}`);\nif (helmetFile) JSON.parse(readFileSync(helmetFile, 'utf8')); // throws early with a clear message","typeGuard":"const helmetFileReadable = (p: string): boolean => { try { statSync(p).isFile(); return true; } catch { return false; } };","tryCatchPattern":"try { startServer(); } catch (e) { if ((e as Error).message.startsWith('Failed to read helmet file')) { console.error(`Check IMMICH_HELMET_FILE (${process.env.IMMICH_HELMET_FILE}) exists, is a readable file, and contains valid JSON`, e.cause); process.exit(1); } throw e; }","preventionTips":["Always copy helmet.json into the build folder in Dockerfiles","Use an absolute IMMICH_HELMET_FILE path in deployments rather than the 'true' default","Validate custom helmet.json with a JSON linter before mounting it","Add a healthcheck/startup check that stats the helmet file"],"tags":["config","filesystem","json","startup"],"backgroundTag":"file-read-failed","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}