{"record":{"id":"11ef79acf7a989fe","repo":"hexojs/hexo","slug":"draft-slug-does-not-exist","errorCode":null,"errorMessage":"Draft \"${slug}\" does not exist.","messagePattern":"Draft \"(.+?)\" does not exist\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/hexo/post.ts","lineNumber":505,"sourceCode":"    }\n\n    if (data.layout === 'draft') data.layout = 'post';\n\n    const ctx = this.context;\n    const { config } = ctx;\n    const draftDir = join(ctx.source_dir, '_drafts');\n    const slug = slugize(data.slug.toString(), { transform: config.filename_case });\n    data.slug = slug;\n    const regex = new RegExp(`^${escapeRegExp(slug)}(?:[^\\\\/\\\\\\\\]+)`);\n    let src = '';\n    const result: Result = {} as any;\n\n    data.layout = (data.layout || config.default_layout).toLowerCase();\n\n    // Find the draft\n    return listDir(draftDir).then(list => {\n      const item = list.find(item => regex.test(item));\n      if (!item) throw new Error(`Draft \"${slug}\" does not exist.`);\n\n      // Read the content\n      src = join(draftDir, item);\n      return readFile(src);\n    }).then(content => {\n      // Create post\n      Object.assign(data, yfmParse(content));\n      data.content = data._content;\n      data._content = undefined;\n\n      return this.create(data, replace as boolean);\n    }).then(post => {\n      result.path = post.path;\n      result.content = post.content;\n      return unlink(src);\n    }).then(() => { // Remove the original draft file\n      if (!config.post_asset_folder) return;\n","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/hexojs/hexo/blob/059cb17494d0632a053c24077f5bcb6ae92acc51/lib/hexo/post.ts#L487-L523","documentation":"Thrown by Post.publish() in lib/hexo/post.ts:505. publish() moves a draft from source/_drafts/ into _posts/: it slugizes data.slug, lists the _drafts directory, and regex-matches a file whose name begins with that slug. If no file matches, it aborts because there is nothing to promote.","triggerScenarios":"hexo.post.publish({ slug: 'foo' }) when no source/_drafts/foo.md (or foo/something) exists; slug casing differs because config.filename_case transformed it (e.g. 1 uppercases the filename but slugize lowercased the input); slug contains characters that slugize stripped; the draft was already published and removed; _drafts directory itself is missing so listDir returns an empty list.","commonSituations":"Typo in the slug passed on the CLI or in code; draft created under a different name or in _posts directly; migrating a project where _drafts was not copied; changing filename_case after drafts were created; calling publish programmatically with a slug sourced from front-matter that is empty or whitespace.","solutions":["List source/_drafts/ and confirm a file starting with the slug exists: ls source/_drafts/.","Create the draft first: hexo new draft <name>, then hexo publish <name>.","Verify data.slug is the exact string you expect (print it) and that slugize did not transform it unexpectedly.","Check config.filename_case (0 = no change, 1 = upper, 2 = lower) and align the draft filename to it.","If _drafts is missing, create it or stop calling publish for non-draft content."],"exampleFix":"// before\nhexo.post.publish({ slug: userInput }).catch(console.error);\n\n// after\nconst draftPath = require('path').join(hexo.source_dir, '_drafts', userInput + '.md');\nrequire('hexo-fs').exists(draftPath).then(exists => {\n  if (!exists) throw new Error(`No draft at ${draftPath}`);\n  return hexo.post.publish({ slug: userInput });\n});","handlingStrategy":"validation","validationCode":"const path = require('path');\nconst { exists, listDir } = require('hexo-fs');\nconst draftDir = path.join(hexo.source_dir, '_drafts');\nconst draftExists = await exists(path.join(draftDir, slug + '.md'));\nif (!draftExists) {\n  const list = await listDir(draftDir).catch(() => []);\n  throw new Error(`No draft for slug '${slug}'. Drafts: ${list.join(', ')}`);\n}\nreturn hexo.post.publish({ slug });","typeGuard":null,"tryCatchPattern":"try {\n  await hexo.post.publish({ slug });\n} catch (e) {\n  if (/Draft .* does not exist/.test(e.message)) {\n    log.warn(`Skipping publish: ${e.message}`);\n  } else throw e;\n}","preventionTips":["Always create drafts with 'hexo new draft <name>' before publishing.","Keep config.filename_case stable to avoid slug/filename case mismatches.","Print the slug before publish to confirm it matches the draft filename."],"tags":["post","draft","publish","filesystem","slug"],"backgroundTag":null,"analyzedSha":"059cb17494d0632a053c24077f5bcb6ae92acc51","analyzedAt":"2026-08-12T20:52:05.731Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}