amir20/dozzle · warning
subscription not found
Error message
subscription not found
What it means
Manager.UpdateSubscription uses a concurrent map Compute on m.subscriptions. The Compute callback receives loaded=false when no subscription exists for the given ID; in that case it stores this error into updateErr and cancels the operation. UpdateSubscription therefore only succeeds for IDs that already exist.
Solutions
- List current subscriptions and use a valid, existing ID for the update.
- If the ID is stale after a restart or concurrent deletion, re-create the subscription instead of updating it.
- Use the error as a signal to refresh the subscription list in the UI before retrying.
Example fix
// before: updating a possibly-stale ID directly
err := manager.UpdateSubscription(id, updates)
// after: verify existence first
if _, ok := manager.GetSubscription(id); !ok {
return fmt.Errorf("subscription %d no longer exists; reload list", id)
}
err := manager.UpdateSubscription(id, updates) Defensive patterns
Strategy: validation
Validate before calling
subs := manager.ListSubscriptions()
if !slices.ContainsFunc(subs, func(s *Subscription) bool { return s.ID == id }) {
return fmt.Errorf("subscription %d does not exist", id)
} Try / catch
err := manager.UpdateSubscription(id, updates)
if err != nil && err.Error() == "subscription not found" {
// refresh list / recreate subscription
return recreateSubscription(updates)
} Prevention
- Re-fetch subscription IDs after any server restart.
- Handle concurrent deletion in UIs (optimistic locking / refresh).
- Never persist numeric subscription IDs across sessions.
When it happens
Trigger: Calling UpdateSubscription(id, updates) with an integer ID that is not present in the manager's subscription map, e.g. after the subscription was deleted, after a process restart (in-memory IDs reset), or with an ID fabricated by the client.
Common situations: Stale UI state where the subscription was deleted in another tab/session before the update was submitted, or a client caching numeric IDs across a server restart.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- (await res.json().catch(() =>
- (await res.json().catch(() =>
- Failed to save destination
- dispatchers fetch failed
- cloud dispatcher missing
AI-assisted analysis of amir20/dozzle@d9463cbe21 (2026-09-07).
Data as JSON: /api/errors/ab2cf1a79a21cc25.
Report an issue: GitHub.
Appendix: source
Thrown at internal/notification/manager.go:143
sub.Enabled = existing.Enabled
} else {
sub.Enabled = true
}
m.subscriptions.Store(sub.ID, sub)
log.Debug().Str("name", sub.Name).Int("id", sub.ID).Msg("Replaced subscription")
m.updateListeners()
return nil
}
// UpdateSubscription updates a subscription with the provided fields
func (m *Manager) UpdateSubscription(id int, updates map[string]any) error {
var updateErr error
_, ok := m.subscriptions.Compute(id, func(sub *Subscription, loaded bool) (*Subscription, xsync.ComputeOp) {
if !loaded {
updateErr = fmt.Errorf("subscription not found")
return nil, xsync.CancelOp
}
// Clone the subscription
updated := &Subscription{
ID: sub.ID,
Name: sub.Name,
Enabled: sub.Enabled,
DispatcherID: sub.DispatcherID,
ContainerExpression: sub.ContainerExpression,
ContainerProgram: sub.ContainerProgram,
LogExpression: sub.LogExpression,
LogProgram: sub.LogProgram,
MetricExpression: sub.MetricExpression,
MetricProgram: sub.MetricProgram,
EventExpression: sub.EventExpression,
EventProgram: sub.EventProgram,
EventCooldowns: sub.EventCooldowns,View on GitHub (pinned to d9463cbe21)