{"record":{"id":"a686a4f852cd4413","repo":"immich-app/immich","slug":"failed-to-write-externalpath-docsmessage","errorCode":null,"errorMessage":"Failed to write \"${externalPath} - ${docsMessage}\"","messagePattern":"Failed to write \"(.+?) - (.+?)\"","errorType":"exception","errorClass":"ImmichStartupError","httpStatus":null,"severity":"critical","filePath":"server/src/services/storage.service.ts","lineNumber":186,"sourceCode":"      this.storageRepository.mkdirSync(folderPath);\n      await this.storageRepository.createFile(internalPath, Buffer.from(Date.now().toString()));\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code === 'EEXIST') {\n        this.logger.warn('Found existing mount file, skipping creation');\n        return;\n      }\n      this.logger.error(`Failed to create ${internalPath}: ${error}`);\n      throw new ImmichStartupError(`Failed to create \"${externalPath} - ${docsMessage}\"`);\n    }\n  }\n\n  private async verifyWriteAccess(folder: StorageFolder) {\n    const { internalPath, externalPath } = this.getMountFilePaths(folder);\n    try {\n      await this.storageRepository.overwriteFile(internalPath, Buffer.from(Date.now().toString()));\n    } catch (error) {\n      this.logger.error(`Failed to write ${internalPath}: ${error}`);\n      throw new ImmichStartupError(`Failed to write \"${externalPath} - ${docsMessage}\"`);\n    }\n  }\n\n  private getMountFilePaths(folder: StorageFolder) {\n    const folderPath = StorageCore.getBaseFolder(folder);\n    const internalPath = join(folderPath, '.immich');\n    const externalPath = `<UPLOAD_LOCATION>/${folder}/.immich`;\n\n    return { folderPath, internalPath, externalPath };\n  }\n}\n","sourceCodeStart":168,"sourceCodeEnd":198,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/storage.service.ts#L168-L198","documentation":"Immich verifies at startup that each configured storage folder (library, upload, thumbs, profile, encoded-video, backups) is writable by writing a probe file (.immich) to the internal mount path. If the test write fails, it throws ImmichStartupError with the external (user-facing) path so the operator can fix the mount. This is a fail-fast guard against a misconfigured or read-only volume.","triggerScenarios":"Server bootstrap calls onBootstrap -> verifyWriteAccess for each StorageFolder; the storageRepository.overwriteFile probe write to '<folder>/.immich' throws (read-only filesystem, nonexistent mount, wrong permissions, volume not mounted).","commonSituations":"Docker volume mounted read-only, host path not mounted into the container, ownership/permissions changed after migration, NFS mount offline, disk full.","solutions":["Mount the folder read/write in the container (remove :ro from the docker-compose volume)","Ensure the directory exists and is owned by the immich user (chown/chmod)","Verify the volume is actually mounted and available (df / ls inside the container)","Check disk space and filesystem errors (dmesg, df -h)"],"exampleFix":"// before\ndocker-compose.yml:\n  volumes:\n    - /mnt/photos:/usr/src/app/upload:ro\n// after\ndocker-compose.yml:\n  volumes:\n    - /mnt/photos:/usr/src/app/upload","handlingStrategy":"try-catch","validationCode":"const probe = join(mountPath, '.immich');\ntry { await fs.access(mountPath, fs.constants.W_OK); } catch { throw new Error(`Mount ${mountPath} is not writable`); }","typeGuard":"null","tryCatchPattern":"try {\n  await startServer();\n} catch (e) {\n  if (e instanceof ImmichStartupError && e.message.includes('Failed to write')) {\n    // check mount permissions/read-only flag and remount rw\n  }\n}","preventionTips":["Mount storage volumes read/write (avoid :ro)","Ensure the immich user owns the storage directories","Pre-check volumes for W_OK before container start","Monitor disk space on storage mounts"],"tags":["storage","filesystem","startup","permissions"],"backgroundTag":"file-write-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"}