hibiken/asynq · error
cannot encode nil scheduler entry
Error message
cannot encode nil scheduler entry
What it means
EncodeSchedulerEntry marshals a *SchedulerEntry (a periodic-task registration with Next/Prev times) into protobuf bytes for persistence. The library throws this when the entry pointer is nil because a nil entry has no ID, spec, or timestamps to encode. It guards proto.Marshal against a nil dereference.
Solutions
- Nil-check each entry before calling EncodeSchedulerEntry and skip nil entries.
- Ensure the code creating SchedulerEntry values always returns a valid struct or an error, never a bare nil pointer.
- If entries come from a registry/map, handle missing keys explicitly instead of storing nil.
Example fix
// before
for _, e := range entries {
b, _ := base.EncodeSchedulerEntry(e) // panics/errors on nil
}
// after
for _, e := range entries {
if e == nil {
continue
}
b, err := base.EncodeSchedulerEntry(e)
if err != nil {
return err
}
} Defensive patterns
Strategy: validation
Validate before calling
if entry == nil {
return errors.New("refusing to encode nil scheduler entry")
} Type guard
func encodableEntry(e *base.SchedulerEntry) bool { return e != nil && e.ID != "" && !e.Spec.IsZero() } Try / catch
b, err := base.EncodeSchedulerEntry(entry)
if err != nil {
return fmt.Errorf("encode scheduler entry %s: %w", entryID, err)
} Prevention
- Skip nil entries when iterating scheduler-entry collections.
- Make entry producers return (entry, error) and never (nil, nil).
- Cover entry construction branches with unit tests.
When it happens
Trigger: Calling base.EncodeSchedulerEntry(nil) directly, or code that iterates scheduler entries and writes each one where the slice contains a nil pointer (e.g. from a failed entry construction or a lookup miss).
Common situations: Custom periodic-task managers syncing entries to Redis where an entry lookup returns nil; tests building SchedulerEntry slices with placeholder nils; refactor changing entry construction so a struct literal assignment is skipped on some branch.
Related errors
- cannot encode nil enqueue event
- cannot encode nil server info
- cannot encode nil worker info
- asynq: unsupported RedisConnOpt type %T
- task id conflicts with another task
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/6dbc7692554ca285.
Report an issue: GitHub.
Appendix: source
Thrown at internal/base/base.go:511
// Payload is the payload of the periodic task.
Payload []byte
// Opts is the options for the periodic task.
Opts []string
// Next shows the next time the task will be enqueued.
Next time.Time
// Prev shows the last time the task was enqueued.
// Zero time if task was never enqueued.
Prev time.Time
}
// EncodeSchedulerEntry marshals the given entry and returns an encoded bytes.
func EncodeSchedulerEntry(entry *SchedulerEntry) ([]byte, error) {
if entry == nil {
return nil, fmt.Errorf("cannot encode nil scheduler entry")
}
next := timestamppb.New(entry.Next)
prev := timestamppb.New(entry.Prev)
return proto.Marshal(&pb.SchedulerEntry{
Id: entry.ID,
Spec: entry.Spec,
TaskType: entry.Type,
TaskPayload: entry.Payload,
EnqueueOptions: entry.Opts,
NextEnqueueTime: next,
PrevEnqueueTime: prev,
})
}
// DecodeSchedulerEntry unmarshals the given bytes and returns a decoded SchedulerEntry.
func DecodeSchedulerEntry(b []byte) (*SchedulerEntry, error) {
var pbmsg pb.SchedulerEntryView on GitHub (pinned to d135f1439b)