{"record":{"id":"b2adb341b9662964","repo":"hexojs/hexo","slug":"name-is-required-b2adb3","errorCode":null,"errorMessage":"name is required","messagePattern":"name is required","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"lib/extend/renderer.ts","lineNumber":101,"sourceCode":"  isRenderable(path: string): boolean {\n    return Boolean(this.get(path));\n  }\n\n  isRenderableSync(path: string): boolean {\n    return Boolean(this.get(path, true));\n  }\n\n  getOutput(path: string): string {\n    const renderer = this.get(path);\n    return renderer ? renderer.output : '';\n  }\n\n  register(name: string, output: string, fn: StoreFunctionWithCallback): void;\n  register(name: string, output: string, fn: StoreFunctionWithCallback, sync: false): void;\n  register(name: string, output: string, fn: StoreSyncFunction, sync: true): void;\n  register(name: string, output: string, fn: StoreFunctionWithCallback | StoreSyncFunction, sync: boolean): void;\n  register(name: string, output: string, fn: StoreFunctionWithCallback | StoreSyncFunction, sync?: boolean) {\n    if (!name) throw new TypeError('name is required');\n    if (!output) throw new TypeError('output is required');\n    if (typeof fn !== 'function') throw new TypeError('fn must be a function');\n\n    name = getExtname(name);\n    output = getExtname(output);\n\n    if (sync) {\n      this.storeSync[name] = fn;\n      this.storeSync[name].output = output;\n\n      this.store[name] = Promise.method(fn);\n      this.store[name].disableNunjucks = (fn as StoreFunction).disableNunjucks;\n    } else {\n      if (fn.length > 2) fn = Promise.promisify(fn);\n      this.store[name] = fn;\n    }\n\n    this.store[name].output = output;","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/hexojs/hexo/blob/059cb17494d0632a053c24077f5bcb6ae92acc51/lib/extend/renderer.ts#L83-L119","documentation":"Thrown by Renderer.register when the 'name' argument is falsy. Renderers convert one file extension to another (e.g. md -> html); the name is the input extension and is required to look the renderer up by path.","triggerScenarios":"Calling hexo.extend.renderer.register('', 'html', fn) or register(undefined, 'html', fn).","commonSituations":"A renderer plugin derives the input extension from config that is empty, or passes a variable that is unset.","solutions":["Pass a non-empty name (input extension, e.g. 'md', 'styl', 'ejs').","Validate the extension source before registering.","Note the name is later passed through getExtname, so include the leading dot or extension."],"exampleFix":"// before\nhexo.extend.renderer.register(ext, 'html', fn);\n// after\nif (ext) hexo.extend.renderer.register(ext, 'html', fn);","handlingStrategy":"validation","validationCode":"if (!name) throw new Error('renderer input name required');\nhexo.extend.renderer.register(name, output, fn);","typeGuard":"const isValidName = (n: unknown): n is string => typeof n === 'string' && n.length > 0;","tryCatchPattern":null,"preventionTips":["Pass the input extension (e.g. 'md') explicitly rather than from loose config.","Validate both name and output in a shared registerRenderer helper.","Test get(path) returns the renderer after registration."],"tags":["renderer","validation","plugin"],"backgroundTag":null,"analyzedSha":"059cb17494d0632a053c24077f5bcb6ae92acc51","analyzedAt":"2026-08-12T20:52:05.731Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}