[BUG] Mods: a local variable named `h` breaks every JSX element in its scope, and `claude plugin validate` passes it

Status Open
Reported on v2.1.296
Maintainer reply None cached
Activity 1 comment · opened Oct 10, 2026

What's Wrong?

JSX in a hooks module compiles against the global h. If the module has a local variable named h (an arrow-function parameter is enough), every JSX element inside that scope calls the local value instead, and the hook throws h is not a function.

claude plugin validate passes the module. It already refuses a shadowed on and $ ("on is declared again (shadowed)"), but not a shadowed h.

In the desktop Code tab the pane then shows only "Nothing to show yet — <plugin> has not drawn in this pane", with no reason. I hit this with HELP.map(h => <Text key={h}>{h}</Text>) and spent a while looking at everything else.

What Should Happen?

claude plugin validate refuses a local h (and Fragment) the same way it refuses on and $, naming the line.

Steps to Reproduce

hooks/register.tsx:

import type { Register } from 'claude-code'

const LINES = ['one', 'two']

export const register: Register = on => {
  on('ui.render', { component: 'Pane', requestId: 'h-shadow' }, async ($, e) => {
    const { Box, Text } = $.ui.resolve(e)
    return (
      <Box flexDirection="column">
        {LINES.map(h => <Text key={h}>{h}</Text>)}
      </Box>
    )
  })
}
  1. claude plugin validate . → ✔ Validation passed with warnings
  2. claude plugin test . with a test that mounts the pane on desktop:

``
(fail) the pane draws
h-shadow's ui.render hook was skipped: h-shadow: h is not a function. (In 'h(Text, {
``

  1. Rename the parameter to line and change nothing else → the same test passes.

Environment

  • Claude Code 2.1.296, Windows 11
  • Desktop Code tab (seen there with 2.1.293)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗