{"record":{"id":"f3858f34fcab973a","repo":"hexojs/hexo","slug":"path-must-be-a-string","errorCode":null,"errorMessage":"path must be a string!","messagePattern":"path must be a string!","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/hexo/router.ts","lineNumber":83,"sourceCode":"          this.emit('error', err);\n        });\n      } else {\n        const bufferData = this._toBuffer(data);\n        if (bufferData) {\n          this.push(bufferData);\n        }\n        this.push(null);\n      }\n    }).catch(err => {\n      this.emit('error', err);\n      this.push(null);\n    });\n  }\n}\n\nconst _format = (path?: string): string => {\n  path = path || '';\n  if (typeof path !== 'string') throw new TypeError('path must be a string!');\n\n  path = path\n    .replace(/^\\/+/, '') // Remove prefixed slashes\n    .replace(/\\\\/g, '/') // Replaces all backslashes\n    .replace(/\\?.*$/, ''); // Remove query string\n\n  // Appends `index.html` to the path with trailing slash\n  if (!path || path.endsWith('/')) {\n    path += 'index.html';\n  }\n\n  return path;\n};\n\nclass Router extends EventEmitter {\n  public routes: {\n    [key: string]: Data | null;\n  };","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/hexojs/hexo/blob/059cb17494d0632a053c24077f5bcb6ae92acc51/lib/hexo/router.ts#L65-L101","documentation":"Thrown by the internal _format() helper in lib/hexo/router.ts:83. _format normalizes a route path (strips leading slashes, flips backslashes, drops query strings, appends index.html). It first does path = path || '' so null/undefined are coerced to '' (no throw); the throw fires only for truthy non-string values.","triggerScenarios":"Calling router.format(123), router.format(true), router.format({}), router.format([]), or router.format(()=>{}). These reach _format via the public format() method (line 114-116).","commonSituations":"Passing a parsed URL object (new URL(...)) instead of url.pathname; passing a number index; a template/helper that interpolates a non-string variable into a route.format call.","solutions":["Coerce to string first: router.format(String(x)) or router.format(typeof x === 'string' ? x : '').","If you have a URL object, pass url.pathname (and strip the query, which _format also does).","Type-check at the call site before invoking format()."],"exampleFix":"// before\nrouter.format(parsedUrl); // parsedUrl is a URL object\n\n// after\nrouter.format(parsedUrl.pathname);","handlingStrategy":"type-guard","validationCode":"if (path != null && typeof path !== 'string') {\n  throw new TypeError(`router.format expects a string, got ${typeof path}`);\n}\nreturn hexo.route.format(path);","typeGuard":"const isRoutePath = (v: unknown): v is string => typeof v === 'string';","tryCatchPattern":null,"preventionTips":["Pass url.pathname from URL objects, not the URL object itself.","Coerce with String() when the value is numeric.","Keep route paths in string-typed collections."],"tags":["router","type-validation","path"],"backgroundTag":null,"analyzedSha":"059cb17494d0632a053c24077f5bcb6ae92acc51","analyzedAt":"2026-08-12T20:52:05.731Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}