{"record":{"id":"6e15f609699a0029","repo":"immich-app/immich","slug":"invalid-import-path-path-message","errorCode":null,"errorMessage":"Invalid import path: ${path.message}","messagePattern":"Invalid import path: (.+?)","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/library.service.ts","lineNumber":351,"sourceCode":"    return validation;\n  }\n\n  async validate(id: string, dto: ValidateLibraryDto): Promise<ValidateLibraryResponseDto> {\n    const importPaths = await Promise.all(\n      (dto.importPaths || []).map((importPath) => this.validateImportPath(importPath)),\n    );\n    return { importPaths };\n  }\n\n  async update(id: string, dto: UpdateLibraryDto): Promise<LibraryResponseDto> {\n    await this.findOrFail(id);\n\n    if (dto.importPaths) {\n      const validation = await this.validate(id, { importPaths: dto.importPaths });\n      if (validation.importPaths) {\n        for (const path of validation.importPaths) {\n          if (!path.isValid) {\n            throw new BadRequestException(`Invalid import path: ${path.message}`);\n          }\n        }\n      }\n    }\n\n    const library = await this.libraryRepository.update(id, dto);\n    return mapLibrary(library);\n  }\n\n  async delete(id: string) {\n    await this.findOrFail(id);\n\n    if (this.watchLibraries) {\n      await this.unwatch(id);\n    }\n\n    await this.libraryRepository.softDelete(id);\n    await this.jobRepository.queue({ name: JobName.LibraryDelete, data: { id } });","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/immich-app/immich/blob/199723261c6ffa897fec8ccdaea6359e39c37cc3/server/src/services/library.service.ts#L333-L369","documentation":"When updating a library with new importPaths, Immich validates each path (existence, permissions, that it is not inside the library's own exclusion paths, etc.) before persisting. If any path fails validation (path.isValid === false), update aborts with 400 BadRequestException carrying path.message describing why. This prevents recording import paths the worker cannot actually scan.","triggerScenarios":"PUT /libraries/{id} with importPaths containing a path that does not exist, is not readable by the Immich process, is a file rather than a directory, or is otherwise invalid per validate().","commonSituations":"Mounting host folders incorrectly in Docker so the path is missing inside the container; pointing at a path owned by root with no read permission; typos in the path; passing a file path instead of a directory.","solutions":["Read path.message in the response - it states the exact reason (missing, no access, etc.).","Ensure the directory exists and is readable by the Immich container user; fix Docker volume mounts so the path is visible inside the container.","Remove or correct the offending import path from the update payload and retry.","On the host: ls -ld <path> and chmod/chown so the immich user can traverse and read it."],"exampleFix":"# before: path not mounted into container\nimportPaths: ['/data/photos']  # missing in container\n# after\ndocker run -v /host/photos:/data/photos:ro ...\n# then PUT /libraries/{id} with importPaths: ['/data/photos']","handlingStrategy":"validation","validationCode":"import { promises as fs } from 'fs';\nasync function assertImportPathsReadable(paths: string[]) {\n  for (const p of paths) {\n    const stat = await fs.stat(p).catch(() => null);\n    if (!stat?.isDirectory()) throw new Error(`Invalid import path: ${p} (missing or not a directory)`);\n    await fs.access(p, fs.constants.R_OK);\n  }\n}","typeGuard":"const isReadableDir = async (p: string) => {\n  const s = await fs.stat(p).catch(() => null);\n  return !!s?.isDirectory();\n};","tryCatchPattern":"try {\n  await api.libraryApi.update(id, { importPaths });\n} catch (e) {\n  if (e.status === 400 && /Invalid import path/.test(e.message)) {\n    // read e.response.message for which path failed and why, fix mounts, retry\n  } else throw e;\n}","preventionTips":["Inside the container, validate each path exists and is readable before saving.","Mount host photo directories into the container with correct ownership.","Surface the per-path message from the API to the operator."],"tags":["api","library","validation","filesystem","permissions","docker","bad-request","immich","nestjs"],"backgroundTag":null,"analyzedSha":"199723261c6ffa897fec8ccdaea6359e39c37cc3","analyzedAt":"2026-08-12T04:54:27.085Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}