immich-app/immich · critical · ImmichStartupError

Failed to read: " ( )

Error message

Failed to read: "${externalPath} (${internalPath}) - ${docsMessage}"

What it means

During bootstrap, Immich verifies it can read a mount-check file inside each configured storage folder; if readFile on the internal path fails, it raises an ImmichStartupError naming the external path, because the storage location is not usable (missing volume, permissions, or wrong mount).

Solutions

  1. Verify the volume is mounted and contains the data (docker inspect / ls the host path) and start the mount before Immich.
  2. Fix filesystem permissions so the Immich process user can read the folder (chown/chmod the data directory).
  3. Check the internal/external path mapping (IMMICH_MEDIA_LOCATION / storage folder config) points at the real mounted directory.
  4. Recreate the missing mount check file (.immich) if the folder exists but the file was deleted, after confirming the mount is correct.

Example fix

// before (docker-compose.yml)
volumes:
  - ./upload:/usr/src/app/upload
// after — ensure the host dir exists with correct ownership
// $ mkdir -p ./upload && chown -R 1000:1000 ./upload
volumes:
  - ./upload:/usr/src/app/upload
Defensive patterns

Strategy: try-catch

Validate before calling

// before starting, verify each storage folder is readable by the immich user
import { accessSync, constants } from 'node:fs';
for (const dir of storageFolders) accessSync(dir, constants.R_OK);

Try / catch

try {
  await startImmichServer();
} catch (e) {
  if (/Failed to read:/.test(String(e.message))) {
    // check volume mount, permissions, and IMMICH_MEDIA_LOCATION mapping, then restart
    process.exit(1);
  } else throw e;
}

Prevention

When it happens

Trigger: Starting Immich when the upload/library volume is not mounted, the folder or .immich mount file is missing, or the process lacks read permission on the internal path.

Common situations: Docker volume failed to mount (host path absent); permissions changed on the host directory; NFS/network mount offline at startup; internal/external path mapping wrong for the storage folder.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/709b90fb818390d5. Report an issue: GitHub.

Appendix: source

Thrown at server/src/services/storage.service.ts:161

      }

      try {
        await this.storageRepository.unlink(file);
      } catch (error: any) {
        this.logger.warn('Unable to remove file from disk', error);
      }
    }

    return JobStatus.Success;
  }

  private async verifyReadAccess(folder: StorageFolder) {
    const { internalPath, externalPath } = this.getMountFilePaths(folder);
    try {
      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}"`);
    }
  }

View on GitHub (pinned to e55ac299a4)