larksuite/cli · error
%s %q: hookName must match ^[a-z0-9][a-z0-9-]*$
Error message
%s %q: hookName must match ^[a-z0-9][a-z0-9-]*$
What it means
validateHookName enforces that every hook registered on a plugin Builder matches the same grammar as plugin names: ^[a-z0-9][a-z0-9-]*$. The rejected action is skipped and the error is recorded on the Builder, surfaced when the plugin is built.
Source
Thrown at extension/platform/builder.go:239
//
// func init() { platform.Register(platform.NewPlugin(...).MustBuild()) }
//
// A panic in init runs before the framework's recover guard is
// installed and will crash the binary. That is the intended
// behaviour: a misconfigured plugin must NOT be silently registered.
func (b *Builder) MustBuild() Plugin {
p, err := b.Build()
if err != nil {
panic(fmt.Sprintf("plugin %q: %v", b.name, err))
}
return p
}
// validateHookName checks the grammar and uniqueness; returns false
// when the name was rejected (caller skips the action).
func (b *Builder) validateHookName(hookName, kind string) bool {
if !pluginNamePattern.MatchString(hookName) {
b.errs = append(b.errs, fmt.Errorf(
"%s %q: hookName must match ^[a-z0-9][a-z0-9-]*$", kind, hookName))
return false
}
if b.hookNames[hookName] {
b.errs = append(b.errs, fmt.Errorf(
"%s %q: hookName already used in this plugin", kind, hookName))
return false
}
b.hookNames[hookName] = true
return true
}
// builtPlugin is the Plugin implementation the builder emits.
type builtPlugin struct {
name string
version string
caps Capabilities
actions []func(Registrar)View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Rename the hook to lowercase kebab-case, e.g. "message-received"
- Ensure the hook name starts with [a-z0-9], not '-' or an uppercase letter
- If the hook name derives from an external event type, map it to a canonical kebab-case name first
- After fixing, rebuild the plugin and confirm no errs accumulate
Example fix
// before
b.On("onMessage_received", handler)
// after
b.On("message-received", handler) Defensive patterns
Strategy: validation
Validate before calling
var hookNameRe = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
func validHook(n string) bool { return hookNameRe.MatchString(n) } Try / catch
b.On(hook, handler) // registration with invalid name is skipped; check after:
for _, e := range b.Errs() { log.Printf("plugin build: %v", e) } Prevention
- Centralize hook-name generation in one kebab-case helper
- Table-test all hook names against the regex
- Map external event names to canonical hook names explicitly
- Don't paste event type strings (with dots/underscores) as hook names
When it happens
Trigger: Calling Observer, Wrap, or On with a hookName containing uppercase letters, underscores, or starting with a hyphen, e.g. b.On("onMessage_received", ...).
Common situations: Using Go-style or event-style names (snake_case, camelCase) for hooks; copying event type names that contain dots or underscores into hook names.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- invalid plugin name %q: must match ^[a-z0-9][a-z0-9-]*$
- %s %q: hookName already used in this plugin
- invalid identity %q: must be user|bot
- invalid risk %q: must be read|write|high-risk-write
- hook %q panic: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/7e90d6cec624f1e8.
Report an issue: GitHub.