sipeed/picoclaw · error
events: handler is nil
Error message
events: handler is nil
What it means
Returned by EventChannel.Subscribe and EventChannel.SubscribeOnce (channel.go:55,72) when the handler argument is nil. The channel-based variant SubscribeChan takes no handler and is the intended API when you want events on a <-chan Event instead of a callback.
Source
Thrown at pkg/events/subscription.go:19
package events
import (
"context"
"errors"
"log"
"runtime/debug"
"sync"
"sync/atomic"
"time"
)
const defaultSubscriberBuffer = 16
var (
// ErrBusClosed is returned when subscribing to a closed event bus.
ErrBusClosed = errors.New("events: bus is closed")
// ErrNilHandler is returned when subscribing without a handler.
ErrNilHandler = errors.New("events: handler is nil")
)
// Handler processes a runtime event delivered to a subscription.
type Handler func(context.Context, Event) error
// SubscribeOptions controls how a subscription receives events.
type SubscribeOptions struct {
Name string
Buffer int
Priority int
Concurrency ConcurrencyKind
Backpressure BackpressurePolicy
// Timeout bounds how long the subscription worker waits for one handler call.
// Handlers should still honor ctx cancellation; timed-out calls keep running
// until their handler returns.
Timeout time.Duration
PanicPolicy PanicPolicy
}View on GitHub (pinned to 49183d7e8d)
Solutions
- Pass a non-nil events.Handler callback to Subscribe/SubscribeOnce
- If you want events on a channel, call SubscribeChan(ctx, opts) which returns (Subscription, <-chan Event, error) and requires no handler
- Guard before subscribing: if handler == nil { return errors.New("handler required") } at the call site
Example fix
// before
var h events.Handler // nil
sub, err := ch.Subscribe(ctx, opts, h)
// after
sub, eventsCh, err := ch.SubscribeChan(ctx, opts) // channel-based, no handler
// or: h := func(ctx context.Context, e events.Event) error { return nil } Defensive patterns
Strategy: validation
Validate before calling
if handler == nil {
return fmt.Errorf("events handler required for Subscribe")
}
sub, err := ch.Subscribe(ctx, opts, handler) Try / catch
sub, err := ch.Subscribe(ctx, opts, handler)
if err != nil && errors.Is(err, events.ErrNilHandler) {
// programmer error: fix the call site; consider falling back to SubscribeChan
} Prevention
- Use SubscribeChan when you want a channel instead of passing nil
- Initialize handler variables at declaration; avoid conditional assignment that can leave them nil
- In tests, always pass a stub handler func
When it happens
Trigger: Passing a nil events.Handler (e.g. a func variable that was never assigned, or a conditional handler that evaluated to nil) to Subscribe or SubscribeOnce.
Common situations: Handler selected by a map/switch that misses a case and leaves the variable nil; refactoring a SubscribeChan call to Subscribe and forgetting to pass the handler; tests registering a stub that is nil.
Related errors
- unsupported observe event %q
- ${label} must be a JSON object.
- ${label}.${key} must be a string.
- Enter and confirm the new login password.
- The login passwords do not match.
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/55995402cfcecce2.
Report an issue: GitHub.