hibiken/asynq · error
asynq: no scheduler entry found
Error message
asynq: no scheduler entry found
What it means
Scheduler.Unregister returns this error when no entry with the given entryID exists in the scheduler's idmap. Unregister only removes known entries; deleting an unknown ID is treated as a caller mistake and reported instead of being silently ignored.
Solutions
- Only call Unregister for IDs previously returned/accepted by Register
- Ignore or special-case this error if best-effort removal is intended (idempotent delete)
- Track registered IDs in your own set and check membership before Unregister
Example fix
// before
if err := s.Unregister(id); err != nil { return err }
// after
if err := s.Unregister(id); err != nil && !strings.Contains(err.Error(), "no scheduler entry found") {
return err
} Defensive patterns
Strategy: type-guard
Validate before calling
if !registered[id] {
return nil // nothing to unregister
} Type guard
func canUnregister(s *asynq.Scheduler, id string) bool {
return s != nil && registeredEntries[id]
} Try / catch
if err := s.Unregister(id); err != nil {
if strings.Contains(err.Error(), "no scheduler entry found") {
return nil // already gone; treat as idempotent success
}
return err
} Prevention
- Keep your own set of successfully Register-ed IDs and only Unregister those
- Make removal paths idempotent by tolerating the not-found error
- Use a single owner for registration/unregistration to avoid double deletes
When it happens
Trigger: Calling s.Unregister(id) for an ID that was never Register-ed, was already unregistered, or whose registration failed; ID mismatch due to formatting (whitespace, case).
Common situations: Unregistering tasks from a config store when the entry was deleted elsewhere first; duplicate cleanup paths unregistering the same ID twice; restart wiping in-memory entries while callers still hold old IDs.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- asynq
- PeriodicTaskConfig.Cronspec cannot be empty
- asynq
- asynq: the scheduler is already running
- asynq: the scheduler has already been stopped
AI-assisted analysis of hibiken/asynq@d135f1439b (2026-09-07).
Data as JSON: /api/errors/7f0dcfbbf6b51c17.
Report an issue: GitHub.
Appendix: source
Thrown at scheduler.go:239
}
cronID, err := s.cron.AddJob(cronspec, job)
if err != nil {
return "", err
}
s.mu.Lock()
s.idmap[job.id.String()] = cronID
s.mu.Unlock()
return job.id.String(), nil
}
// Unregister removes a registered entry by entry ID.
// Unregister returns a non-nil error if no entries were found for the given entryID.
func (s *Scheduler) Unregister(entryID string) error {
s.mu.Lock()
defer s.mu.Unlock()
cronID, ok := s.idmap[entryID]
if !ok {
return fmt.Errorf("asynq: no scheduler entry found")
}
delete(s.idmap, entryID)
s.cron.Remove(cronID)
return nil
}
// Run starts the scheduler until an os signal to exit the program is received.
// It returns an error if scheduler is already running or has been shutdown.
func (s *Scheduler) Run() error {
if err := s.Start(); err != nil {
return err
}
s.waitForSignals()
s.Shutdown()
return nil
}
// Start starts the scheduler.View on GitHub (pinned to d135f1439b)