honojs/hono · error · Error
Invalid JSX tag name: ${tag}
Error message
Invalid JSX tag name: ${tag} What it means
Hono's JSX runtime validates tag names when constructing a JSXNode: a tag must either be a function component or a string that is a valid HTML/SVG element name or a valid custom-element name. If it's a string that fails isValidTagName (e.g. contains invalid characters, is empty, or isn't a recognized element/custom element), this error is thrown.
Source
Thrown at src/jsx/base.ts:179
export type Child =
| string
| Promise<string>
| number
| JSXNode
| null
| undefined
| boolean
| Child[]
export class JSXNode implements HtmlEscaped {
tag: string | Function
props: Props
key?: string
children: Child[]
isEscaped: true = true as const
constructor(tag: string | Function, props: Props, children: Child[]) {
if (typeof tag !== 'function' && !isValidTagName(tag)) {
throw new Error(`Invalid JSX tag name: ${tag}`)
}
this.tag = tag
this.props = props
this.children = children
}
get type(): string | Function {
return this.tag as string
}
// Added for compatibility with libraries that rely on React's internal structure
// eslint-disable-next-line @typescript-eslint/no-explicit-any
get ref(): any {
return this.props.ref || null
}
toString(): string | Promise<string> {
const render = () => {View on GitHub (pinned to e2740d5a1b)
Solutions
- Check that the component variable is actually imported and not undefined; fix the import path/export name
- If you meant a custom element, rename it to include a hyphen and valid characters (e.g. `my-element`)
- If the tag is dynamic, validate/whitelist the string before interpolating it into JSX
- Capitalize component variables so JSX treats them as function references, not tag names
Example fix
// before const tag = someInput // e.g. 'My Widget' or undefined return <tag>hi</tag> // after const tag = typeof someTag === 'string' && /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(someTag) ? someTag : 'div' return <tag>hi</tag>
Defensive patterns
Strategy: type-guard
Validate before calling
const isValidElementName = (s: string) => /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/.test(s) || /[A-Z]/.test(s) const Tag = trustedTags.includes(name) ? name : 'div'
Type guard
const isJsxTag = (t: unknown): t is string | Function => typeof t === 'function' || (typeof t === 'string' && (HTMLElementTags.includes(t) || /^[a-z][a-z0-9]*(-[a-z0-9]+)+$/.test(t)))
Try / catch
null
Prevention
- Verify component imports resolve to functions (avoid undefined lowercase tags)
- Keep dynamic tag names in a whitelist
- Name custom elements with a hyphen and lowercase alphanumeric characters
When it happens
Trigger: Rendering `<my-component>` where the string is not a valid custom-element name (must contain a hyphen with lowercase letters, like `my-element`); using a variable that is undefined/null/empty as a JSX tag (lowercase JSX tags that resolve to strings); dynamically building tag names like `<{"div" + suffix}>` producing an invalid name.
Common situations: Importing a component that resolves to undefined due to a missing/circular export and using it with a lowercase name; typos in intrinsic elements; attempting dynamic tag names with characters invalid in tag names (dots, spaces); forgetting that lowercase JSX tags referencing variables must be valid element or custom-element names.
Related errors
- Can only set one of `children` or `props.dangerouslySetInner
- Invalid prop '${key}' of type 'function' supplied to '${tag}
- Children.only() expects only one child
- Cannot update an unmounted root
- style sheet not found
AI-assisted analysis of honojs/hono@e2740d5a1b (2026-08-28).
Data as JSON: /api/errors/bbc7639d5283026e.
Report an issue: GitHub.