{"record":{"id":"72775df132722dd9","repo":"immich-app/immich","slug":"tag-not-found","errorCode":null,"errorMessage":"Tag not found","messagePattern":"Tag not found","errorType":"exception","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"server/src/services/tag.service.ts","lineNumber":42,"sourceCode":"export class TagService extends BaseService {\n  async getAll(auth: AuthDto) {\n    const tags = await this.tagRepository.getAll(auth.user.id);\n    return tags.map((tag) => mapTag(tag));\n  }\n\n  async get(auth: AuthDto, id: string): Promise<TagResponseDto> {\n    await this.requireAccess({ auth, permission: Permission.TagRead, ids: [id] });\n    const tag = await this.findOrFail(id);\n    return mapTag(tag);\n  }\n\n  async create(auth: AuthDto, dto: TagCreateDto) {\n    let parent;\n    if (dto.parentId) {\n      await this.requireAccess({ auth, permission: Permission.TagRead, ids: [dto.parentId] });\n      parent = await this.tagRepository.get(dto.parentId);\n      if (!parent) {\n        throw new BadRequestException('Tag not found');\n      }\n    }\n\n    const userId = auth.user.id;\n    const value = parent ? `${parent.value}/${dto.name}` : dto.name;\n    const duplicate = await this.tagRepository.getByValue(userId, value);\n    if (duplicate) {\n      throw new BadRequestException(`A tag with that name already exists`);\n    }\n\n    const { color } = dto;\n    const tag = await this.tagRepository.create({ userId, value, color, parentId: parent?.id });\n\n    return mapTag(tag);\n  }\n\n  async update(auth: AuthDto, id: string, dto: TagUpdateDto): Promise<TagResponseDto> {\n    await this.requireAccess({ auth, permission: Permission.TagUpdate, ids: [id] });","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/server/src/services/tag.service.ts#L24-L60","documentation":"Thrown by TagService.create when the client supplies a parentId but no tag with that ID exists in the repository. The service resolves the parent before composing the child tag's value path, so a missing parent blocks creation. It is a 400 BadRequest because the request references a nonexistent resource.","triggerScenarios":"POST /api/tags (or TagService.create) with dto.parentId set to a tag ID that does not exist — e.g. deleted tag, stale ID from another client, or an ID belonging to a different user.","commonSituations":"Client kept a cached tag list after a parent tag was deleted; UI autocomplete sent a stale ID; copying API examples with fabricated UUIDs; creating child tags before the parent via parallel requests.","solutions":["Verify the parentId exists (GET /api/tags) before creating the child tag","Create the parent tag first, then use its returned id as parentId","Pass parentId: null/undefined to create a root-level tag instead","Clear stale local caches and refresh the tag list in the client"],"exampleFix":"// before\nawait api.createTag({ name: 'kids', parentId: 'stale-id' });\n// after\nconst tags = await api.getAllTags();\nconst parent = tags.find(t => t.value === 'parents');\nif (!parent) throw new Error('create parent tag first');\nawait api.createTag({ name: 'kids', parentId: parent.id });","handlingStrategy":"validation","validationCode":"const tags = await api.getAllTags();\nif (dto.parentId && !tags.some(t => t.id === dto.parentId)) {\n  throw new Error(`parent tag ${dto.parentId} does not exist`);\n}","typeGuard":null,"tryCatchPattern":"try { await api.createTag(dto); } catch (e) {\n  if (e.response?.status === 400 && e.response?.data?.message === 'Tag not found') {\n    // create as root tag or refresh tag list\n  }\n}","preventionTips":["Refresh the tag list before nested creation flows","Create parents before children; never create them in parallel","Treat parentId as optional and default to root-level creation"],"tags":["validation","nested-resource"],"backgroundTag":"entity-not-found","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}