{"record":{"id":"fdddb994c88ca5c7","repo":"hexojs/hexo","slug":"path-must-be-a-string-fdddb9","errorCode":null,"errorMessage":"path must be a string!","messagePattern":"path must be a string!","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/plugins/helper/feed_tag.ts","lineNumber":19,"sourceCode":"import { url_for } from 'hexo-util';\nimport moize from 'moize';\nimport type { LocalsType } from '../../types';\n\nconst feedFn = (str = '') => {\n  if (str) return str.replace(/2$/, '');\n  return str;\n};\n\ninterface Options {\n  title?: string;\n  type?: string | null;\n}\n\nfunction makeFeedTag(this: LocalsType, path?: string, options: Options = {}, configFeed?: any, configTitle?: string) {\n  const title = options.title || configTitle;\n\n  if (path) {\n    if (typeof path !== 'string') throw new TypeError('path must be a string!');\n\n    let type = feedFn(options.type);\n\n    if (!type) {\n      if (path.includes('atom')) type = 'atom';\n      else if (path.includes('rss')) type = 'rss';\n    }\n\n    const typeAttr = type ? `type=\"application/${type}+xml\"` : '';\n\n    return `<link rel=\"alternate\" href=\"${url_for.call(this, path)}\" title=\"${title}\" ${typeAttr}>`;\n  }\n\n  if (configFeed) {\n    if (configFeed.type && configFeed.path) {\n      if (typeof configFeed.type === 'string') {\n        return `<link rel=\"alternate\" href=\"${url_for.call(this, configFeed.path)}\" title=\"${title}\" type=\"application/${feedFn(configFeed.type)}+xml\">`;\n      }","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/hexojs/hexo/blob/059cb17494d0632a053c24077f5bcb6ae92acc51/lib/plugins/helper/feed_tag.ts#L1-L37","documentation":"Thrown by the feed_tag helper's makeFeedTag() (lib/plugins/helper/feed_tag.ts:19). The helper builds an RSS/Atom <link> tag. If a path argument is truthy but not a string (number, object, array), it is rejected. A falsy path falls through to the config.feed branch and does not throw.","triggerScenarios":"Calling <%- feed_tag(123) %> or feed_tag(someObject) from a template; passing a parsed URL object; a variable that was expected to be a path string but resolved to a number/object.","commonSituations":"Theme template passing a config value that is a number or object; refactor of the helper call leaving a non-string; passing an array of paths instead of iterating.","solutions":["Pass a string path: <%- feed_tag('atom.xml') %>.","Coerce: <%- feed_tag(String(x)) %> when x may be non-string.","If you have multiple feed paths, loop and call feed_tag once per string."],"exampleFix":"<!-- before -->\n<%- feed_tag(feedConfig.path) %>\n\n<!-- after -->\n<%- typeof feedConfig.path === 'string' ? feed_tag(feedConfig.path) : '' %>","handlingStrategy":"type-guard","validationCode":"if (path != null && typeof path !== 'string') {\n  throw new TypeError(`feed_tag path must be a string, got ${typeof path}`);\n}\nreturn hexo.extend.helper.get('feed_tag').call(hexo.locals, path);","typeGuard":"const isFeedPath = (v: unknown): v is string => typeof v === 'string' && v.length > 0;","tryCatchPattern":null,"preventionTips":["Pass literal feed paths in templates (e.g. 'atom.xml').","Coerce dynamic values with String() and guard undefined.","Validate config.feed.path is a string before forwarding to the helper."],"tags":["helper","feed","type-validation","template"],"backgroundTag":null,"analyzedSha":"059cb17494d0632a053c24077f5bcb6ae92acc51","analyzedAt":"2026-08-12T20:52:05.731Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}