hexojs/hexo · error · Error
Tag \`${name}\` has already existed!
Error message
Tag \`${name}\` has already existed! What it means
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.
Source
Thrown at lib/models/tag.ts:62
Tag.virtual('length').get(function() {
// Note: this.posts.length is also working
// But it's slow because `find` has to iterate over all posts
const ReadOnlyPostTag = ctx._binaryRelationIndex.post_tag;
return ReadOnlyPostTag.find({tag_id: this._id}).length;
});
// Check whether a tag exists
Tag.pre('save', (data: TagSchema) => {
const { name } = data;
if (!name) return;
const Tag = ctx.model('Tag');
const tag = Tag.findOne({name}, {lean: true});
if (tag) {
throw new Error(`Tag \`${name}\` has already existed!`);
}
});
// Remove PostTag references
Tag.pre('remove', (data: TagSchema) => {
const PostTag = ctx.model('PostTag');
return PostTag.remove({tag_id: data._id});
});
return Tag;
};
View on GitHub (pinned to 059cb17494)
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.
Example fix
// before
ctx.model('Tag').insert({ name });
// after
const Tag = ctx.model('Tag');
const dup = Tag.findOne({ name }, { lean: true });
if (!dup) Tag.insert({ name }); Defensive patterns
Strategy: validation
Validate before calling
const Tag = hexo.model('Tag');
const dup = Tag.findOne({ name }, { lean: true });
if (dup) {
throw new Error(`Tag '${name}' already exists (id=${dup._id})`);
}
Tag.insert({ name }); Try / catch
try {
Tag.insert({ name });
} catch (e) {
if (/has already existed/.test(e.message)) {
return Tag.findOne({ name }, { lean: true });
}
throw e;
} Prevention
- Run hexo clean before re-importing.
- Use front-matter tag processing for automatic dedup.
- Check findOne({ name }) before any Tag.insert.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Category \`${name}\` has already existed!
- name is required
- `${value}` is not a valid date!
- fn must be a function
- name is required
AI-assisted analysis of hexojs/hexo@059cb17494 (2026-08-12).
Data as JSON: /api/errors/7365e91e1d2f88fd.
Report an issue: GitHub.