immich-app/immich · critical · ImmichStartupError
Failed to write
Error message
Failed to write "${externalPath} - ${docsMessage}" What it means
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.
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)
Example fix
// before
docker-compose.yml:
volumes:
- /mnt/photos:/usr/src/app/upload:ro
// after
docker-compose.yml:
volumes:
- /mnt/photos:/usr/src/app/upload Defensive patterns
Strategy: try-catch
Validate before calling
const probe = join(mountPath, '.immich');
try { await fs.access(mountPath, fs.constants.W_OK); } catch { throw new Error(`Mount ${mountPath} is not writable`); } Type guard
null
Try / catch
try {
await startServer();
} catch (e) {
if (e instanceof ImmichStartupError && e.message.includes('Failed to write')) {
// check mount permissions/read-only flag and remount rw
}
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: Docker volume mounted read-only, host path not mounted into the container, ownership/permissions changed after migration, NFS mount offline, disk full.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to create
- Failed to read: " ( )
- Detected an inconsistent media location. For more…
- Failed to read helmet file
- Attempted to clear cache, but rmtree is not safe on this…
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/a686a4f852cd4413.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/storage.service.ts:186
this.storageRepository.mkdirSync(folderPath);
await this.storageRepository.createFile(internalPath, Buffer.from(Date.now().toString()));
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'EEXIST') {
this.logger.warn('Found existing mount file, skipping creation');
return;
}
this.logger.error(`Failed to create ${internalPath}: ${error}`);
throw new ImmichStartupError(`Failed to create "${externalPath} - ${docsMessage}"`);
}
}
private async verifyWriteAccess(folder: StorageFolder) {
const { internalPath, externalPath } = this.getMountFilePaths(folder);
try {
await this.storageRepository.overwriteFile(internalPath, Buffer.from(Date.now().toString()));
} catch (error) {
this.logger.error(`Failed to write ${internalPath}: ${error}`);
throw new ImmichStartupError(`Failed to write "${externalPath} - ${docsMessage}"`);
}
}
private getMountFilePaths(folder: StorageFolder) {
const folderPath = StorageCore.getBaseFolder(folder);
const internalPath = join(folderPath, '.immich');
const externalPath = `<UPLOAD_LOCATION>/${folder}/.immich`;
return { folderPath, internalPath, externalPath };
}
}
View on GitHub (pinned to e55ac299a4)