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

  1. List current subscriptions and use a valid, existing ID for the update.
  2. If the ID is stale after a restart or concurrent deletion, re-create the subscription instead of updating it.
  3. 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

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


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)