immich-app/immich · critical · ImmichStartupError
Failed to create
Error message
Failed to create "${externalPath} - ${docsMessage}" What it means
During bootstrap, Immich creates a mount-check file per storage folder to validate write access; if creation fails with an error other than EEXIST, it raises an ImmichStartupError naming the external path, because Immich cannot write to the configured storage location.
Solutions
- Fix ownership/permissions so the Immich user can write: chown -R <uid>:<gid> on the data directory (commonly 1000:1000).
- Remove ':ro' from the volume mount if present and remount the volume read-write.
- Pre-create the host folder with correct ownership so Docker doesn't create it as root.
- Check disk space / mount health (df -h, mount status) if permissions look correct.
Example fix
// before (docker-compose.yml) volumes: - ./upload:/usr/src/app/upload:ro // after volumes: - ./upload:/usr/src/app/upload // plus: chown -R 1000:1000 ./upload
Defensive patterns
Strategy: try-catch
Validate before calling
// before starting, verify each storage folder is writable by the immich user
import { accessSync, constants } from 'node:fs';
for (const dir of storageFolders) accessSync(dir, constants.W_OK); Try / catch
try {
await startImmichServer();
} catch (e) {
if (/Failed to create \"/.test(String(e.message))) {
// fix ownership/permissions or read-only mount, then restart
process.exit(1);
} else throw e;
} Prevention
- Pre-create host folders with correct UID/GID ownership (e.g. 1000:1000)
- Never mount storage folders read-only
- Avoid NFS root-squash mismatches for the data volume
- Check disk space and mount writability in deployment checks
When it happens
Trigger: Starting Immich when the storage folder is read-only, the volume is mounted but the process user lacks write permission, or the folder doesn't exist and cannot be created.
Common situations: Bind mounts owned by root while Immich runs as another UID; read-only volume mounts (':ro'); disk-full or NFS with root-squash; missing host directory in docker-compose so Docker creates a root-owned folder.
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 read: " ( )
- Failed to write
- Detected an inconsistent media location. For more…
- Failed to read helmet file
- Skipping move due to file size mismatch
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/c86aae6c7152ff4f.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/storage.service.ts:176
await this.storageRepository.readFile(internalPath);
} catch (error) {
this.logger.error(`Failed to read (${internalPath}): ${error}`);
throw new ImmichStartupError(`Failed to read: "${externalPath} (${internalPath}) - ${docsMessage}"`);
}
}
private async createMountFile(folder: StorageFolder) {
const { folderPath, internalPath, externalPath } = this.getMountFilePaths(folder);
try {
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`;
View on GitHub (pinned to e55ac299a4)