immich-app/immich · error · BadRequestException

Sidecar files cannot be deleted

Error message

Sidecar files cannot be deleted

What it means

Raised by AssetFileService.delete when the target file record represents a sidecar (e.g. XMP metadata) file rather than a primary asset file. Sidecars are managed automatically alongside their parent asset, so direct deletion through this endpoint is blocked; the offending input is the asset file id.

Solutions

  1. Delete the parent asset instead, which removes its sidecars as part of asset deletion
  2. Let Immich regenerate/drop sidecars via its metadata workflows rather than deleting the file record directly
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at server/src/services/asset-file.service.ts:42 when the library encounters an invalid state.

Common situations: See trigger scenarios.


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

Appendix: source

Thrown at server/src/services/asset-file.service.ts:42

  async download(auth: AuthDto, id: string) {
    await this.requireAccess({ auth, permission: Permission.AssetFileDownload, ids: [id] });
    const file = await findOrFail(() => this.assetFileRepository.get(id), 'Asset file');

    return new ImmichFileResponse({
      path: file.path,
      fileName: getFileNameWithoutExtension(file.path) + getFilenameExtension(file.path),
      contentType: mimeTypes.lookup(file.path),
      cacheControl: CacheControl.PrivateWithCache,
    });
  }

  async delete(auth: AuthDto, id: string) {
    await this.requireAccess({ auth, permission: Permission.AssetFileDelete, ids: [id] });

    const file = await findOrFail(() => this.assetFileRepository.get(id), 'Asset file');
    // TODO consider implications of allowing sidecar files to be deleted
    if (file.type === AssetFileType.Sidecar) {
      throw new BadRequestException('Sidecar files cannot be deleted');
    }

    await this.assetFileRepository.delete(id);
    await this.jobRepository.queue({ name: JobName.FileDelete, data: { files: [file.path] } });
  }
}

View on GitHub (pinned to e55ac299a4)