{"record":{"id":"7365e91e1d2f88fd","repo":"hexojs/hexo","slug":"tag-name-has-already-existed","errorCode":null,"errorMessage":"Tag \\`${name}\\` has already existed!","messagePattern":"Tag \\\\`(.+?)\\\\` has already existed!","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/models/tag.ts","lineNumber":62,"sourceCode":"\n  Tag.virtual('length').get(function() {\n    // Note: this.posts.length is also working\n    // But it's slow because `find` has to iterate over all posts\n    const ReadOnlyPostTag = ctx._binaryRelationIndex.post_tag;\n\n    return ReadOnlyPostTag.find({tag_id: this._id}).length;\n  });\n\n  // Check whether a tag exists\n  Tag.pre('save', (data: TagSchema) => {\n    const { name } = data;\n    if (!name) return;\n\n    const Tag = ctx.model('Tag');\n    const tag = Tag.findOne({name}, {lean: true});\n\n    if (tag) {\n      throw new Error(`Tag \\`${name}\\` has already existed!`);\n    }\n  });\n\n  // Remove PostTag references\n  Tag.pre('remove', (data: TagSchema) => {\n    const PostTag = ctx.model('PostTag');\n    return PostTag.remove({tag_id: data._id});\n  });\n\n  return Tag;\n};\n","sourceCodeStart":44,"sourceCodeEnd":74,"githubUrl":"https://github.com/hexojs/hexo/blob/059cb17494d0632a053c24077f5bcb6ae92acc51/lib/models/tag.ts#L44-L74","documentation":"Thrown by the Tag model pre('save') hook (lib/models/tag.ts:62). Before a Tag document is saved, the hook queries for an existing tag with the same name; if found, the save is aborted to prevent duplicate tags.","triggerScenarios":"Calling ctx.model('Tag').insert({ name: 'js' }) when a Tag named 'js' already exists; re-importing posts whose front-matter tags collide; a plugin inserting tags without checking.","commonSituations":"Running an import twice without hexo clean; programmatic tag creation that bypasses the dedup logic; case variants that slugize to the same name but differ in stored name; stale db.json.","solutions":["Before insert, query: const exists = ctx.model('Tag').findOne({ name }, { lean: true }); reuse if exists.","Rely on front-matter tag processing which dedupes by name.","Run hexo clean before re-importing to reset the tag store.","Link posts to the existing tag instead of creating a duplicate."],"exampleFix":"// before\nctx.model('Tag').insert({ name });\n\n// after\nconst Tag = ctx.model('Tag');\nconst dup = Tag.findOne({ name }, { lean: true });\nif (!dup) Tag.insert({ name });","handlingStrategy":"validation","validationCode":"const Tag = hexo.model('Tag');\nconst dup = Tag.findOne({ name }, { lean: true });\nif (dup) {\n  throw new Error(`Tag '${name}' already exists (id=${dup._id})`);\n}\nTag.insert({ name });","typeGuard":null,"tryCatchPattern":"try {\n  Tag.insert({ name });\n} catch (e) {\n  if (/has already existed/.test(e.message)) {\n    return Tag.findOne({ name }, { lean: true });\n  }\n  throw e;\n}","preventionTips":["Run hexo clean before re-importing.","Use front-matter tag processing for automatic dedup.","Check findOne({ name }) before any Tag.insert."],"tags":["model","tag","duplicate","database","validation"],"backgroundTag":null,"analyzedSha":"059cb17494d0632a053c24077f5bcb6ae92acc51","analyzedAt":"2026-08-12T20:52:05.731Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}