immich-app/immich · critical · ImmichStartupError

Failed to create "${externalPath} - ${docsMessage}"

Error message

Failed to create "${externalPath} - ${docsMessage}"

What it means

Thrown by StorageService.createMountFile at startup when mkdir of the folder path or creation of the '.immich' marker file fails with an errno other than EEXIST (EEXIST is tolerated). It aborts boot via ImmichStartupError, including the external path and the folder-checks doc link.

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 199723261c)

Solutions

  1. Free space on the target volume and retry boot.
  2. Confirm the bind mount is not ':ro' and the immich uid has write permission to the folder.
  3. Create the parent directory on the host if it is missing, then restart.
  4. On SELinux-enabled hosts, relabel the mount: chcon -Rt container_file_t <host path>.
  5. Inspect the prior log line 'Failed to create <internalPath>: <error>' for the exact errno.

Example fix

chmod -R u+rwX /mnt/immich/upload && chown -R 1000:1000 /mnt/immich/upload
Defensive patterns

Strategy: validation

Validate before calling

import { accessSync, constants, mkdirSync } from 'node:fs';

function ensureWritableDir(p: string) {
  mkdirSync(p, { recursive: true });
  accessSync(p, constants.W_OK | constants.X_OK);
}
// call ensureWritableDir(folderPath) for each StorageFolder before boot

Try / catch

try { await storageService.onBootstrap(); }
catch (e) {
  if (e instanceof ImmichStartupError && /Failed to create/.test(e.message)) {
    // check disk space & permissions, then restart - do not loop
  }
}

Prevention

When it happens

Trigger: Server boot, folder-integrity phase: storageRepository.mkdirSync(folderPath) or createFile(internalPath, ...) throws a non-EEXIST error (e.g. EACCES, ENOSPC, EROFS).

Common situations: Disk full on the volume backing the upload/library folder; read-only filesystem (read-only bind mount or read-only rootfs); SELinux/AppCore denying write; parent directory missing because a prior mount step failed.

Related errors


AI-assisted analysis of immich-app/immich@199723261c (2026-08-12). Data as JSON: /api/errors/c86aae6c7152ff4f. Report an issue: GitHub.