{"record":{"id":"6ef1065910a9dd31","repo":"AdguardTeam/AdGuardHome","slug":"client-q-is-not-found","errorCode":null,"errorMessage":"client %q is not found","messagePattern":"client %q is not found","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/client/storage.go","lineNumber":650,"sourceCode":"}\n\n// Update finds the stored persistent client by its name and updates its\n// information from p.\nfunc (s *Storage) Update(ctx context.Context, name string, p *Persistent) (err error) {\n\tdefer func() { err = errors.Annotate(err, \"updating client: %w\") }()\n\n\terr = p.validate(ctx, s.logger, s.allowedTags)\n\tif err != nil {\n\t\t// Don't wrap the error since there is already an annotation deferred.\n\t\treturn err\n\t}\n\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tstored, ok := s.index.findByName(name)\n\tif !ok {\n\t\treturn fmt.Errorf(\"client %q is not found\", name)\n\t}\n\n\t// Client p has a newly generated UID, so replace it with the stored one.\n\t//\n\t// TODO(s.chzhen):  Remove when frontend starts handling UIDs.\n\tp.UID = stored.UID\n\n\terr = s.index.clashes(p)\n\tif err != nil {\n\t\t// Don't wrap the error since there is already an annotation deferred.\n\t\treturn err\n\t}\n\n\ts.index.remove(stored)\n\ts.index.add(p)\n\n\ts.upstreamManager.updateCustomUpstreamConfig(p)\n","sourceCodeStart":632,"sourceCodeEnd":668,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/client/storage.go#L632-L668","documentation":"Returned by Storage.Update when no stored client with the given name exists. Update only mutates existing clients; it does not create them.","triggerScenarios":"Calling Storage.Update(name, p) where name does not match any client in the index (findByName returns false), e.g. the client was deleted, renamed, or never added.","commonSituations":"Race between a UI edit and a concurrent deletion, renaming a client and updating it under its old name, stale references after a config reload.","solutions":["If the client should exist, re-check its current name with the list/Get API and retry with the correct one","If it was deleted, call Add instead of Update to recreate it","Handle this error explicitly in callers so a missing client triggers Add as a fallback"],"exampleFix":"// before\nerr := s.Update(ctx, \"old-name\", p) // renamed/deleted\n\n// after\nif err := s.Update(ctx, p.Name, p); err != nil {\n    if strings.Contains(err.Error(), \"is not found\") {\n        err = s.Add(ctx, p)\n    }\n}","handlingStrategy":"fallback","validationCode":"if _, ok := s.ClientByName(name); !ok { /* client missing; use Add instead */ }","typeGuard":null,"tryCatchPattern":"if err := s.Update(ctx, name, p); err != nil {\n    if strings.Contains(err.Error(), \"is not found\") {\n        err = s.Add(ctx, p) // upsert fallback\n    }\n}","preventionTips":["Implement Add-or-Update (upsert) semantics at the call site","Refresh client names from storage before edits in long-lived UIs"],"tags":["storage","client","not-found","update"],"backgroundTag":"resource-not-found","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}