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

  1. Rename the hook to lowercase kebab-case, e.g. "message-received"
  2. Ensure the hook name starts with [a-z0-9], not '-' or an uppercase letter
  3. If the hook name derives from an external event type, map it to a canonical kebab-case name first
  4. 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

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


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/7e90d6cec624f1e8. Report an issue: GitHub.