{"record":{"id":"ab2cf1a79a21cc25","repo":"amir20/dozzle","slug":"subscription-not-found","errorCode":null,"errorMessage":"subscription not found","messagePattern":"subscription not found","errorType":"exception","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"internal/notification/manager.go","lineNumber":143,"sourceCode":"\t\tsub.Enabled = existing.Enabled\n\t} else {\n\t\tsub.Enabled = true\n\t}\n\n\tm.subscriptions.Store(sub.ID, sub)\n\tlog.Debug().Str(\"name\", sub.Name).Int(\"id\", sub.ID).Msg(\"Replaced subscription\")\n\n\tm.updateListeners()\n\n\treturn nil\n}\n\n// UpdateSubscription updates a subscription with the provided fields\nfunc (m *Manager) UpdateSubscription(id int, updates map[string]any) error {\n\tvar updateErr error\n\t_, ok := m.subscriptions.Compute(id, func(sub *Subscription, loaded bool) (*Subscription, xsync.ComputeOp) {\n\t\tif !loaded {\n\t\t\tupdateErr = fmt.Errorf(\"subscription not found\")\n\t\t\treturn nil, xsync.CancelOp\n\t\t}\n\n\t\t// Clone the subscription\n\t\tupdated := &Subscription{\n\t\t\tID:                  sub.ID,\n\t\t\tName:                sub.Name,\n\t\t\tEnabled:             sub.Enabled,\n\t\t\tDispatcherID:        sub.DispatcherID,\n\t\t\tContainerExpression: sub.ContainerExpression,\n\t\t\tContainerProgram:    sub.ContainerProgram,\n\t\t\tLogExpression:       sub.LogExpression,\n\t\t\tLogProgram:          sub.LogProgram,\n\t\t\tMetricExpression:    sub.MetricExpression,\n\t\t\tMetricProgram:       sub.MetricProgram,\n\t\t\tEventExpression:     sub.EventExpression,\n\t\t\tEventProgram:        sub.EventProgram,\n\t\t\tEventCooldowns:      sub.EventCooldowns,","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/notification/manager.go#L125-L161","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: updating a possibly-stale ID directly\nerr := manager.UpdateSubscription(id, updates)\n// after: verify existence first\nif _, ok := manager.GetSubscription(id); !ok {\n    return fmt.Errorf(\"subscription %d no longer exists; reload list\", id)\n}\nerr := manager.UpdateSubscription(id, updates)","handlingStrategy":"validation","validationCode":"subs := manager.ListSubscriptions()\nif !slices.ContainsFunc(subs, func(s *Subscription) bool { return s.ID == id }) {\n    return fmt.Errorf(\"subscription %d does not exist\", id)\n}","typeGuard":null,"tryCatchPattern":"err := manager.UpdateSubscription(id, updates)\nif err != nil && err.Error() == \"subscription not found\" {\n    // refresh list / recreate subscription\n    return recreateSubscription(updates)\n}","preventionTips":["Re-fetch subscription IDs after any server restart.","Handle concurrent deletion in UIs (optimistic locking / refresh).","Never persist numeric subscription IDs across sessions."],"tags":["notifications","subscription","crud"],"backgroundTag":"record-not-found","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}