{"record":{"id":"2bc683b9b6fe944d","repo":"micro/go-micro","slug":"could-not-get-next","errorCode":null,"errorMessage":"could not get next","messagePattern":"could not get next","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"registry/etcd/watcher.go","lineNumber":52,"sourceCode":"\tif len(wo.Service) > 0 {\n\t\twatchPath = servicePath(wo.Service) + \"/\"\n\t}\n\n\treturn &etcdWatcher{\n\t\tstop:    stop,\n\t\tw:       r.client.Watch(ctx, watchPath, clientv3.WithPrefix(), clientv3.WithPrevKV()),\n\t\tclient:  r.client,\n\t\ttimeout: timeout,\n\t}, nil\n}\n\nfunc (ew *etcdWatcher) Next() (*registry.Result, error) {\n\tfor wresp := range ew.w {\n\t\tif wresp.Err() != nil {\n\t\t\treturn nil, wresp.Err()\n\t\t}\n\t\tif wresp.Canceled {\n\t\t\treturn nil, errors.New(\"could not get next\")\n\t\t}\n\t\tfor _, ev := range wresp.Events {\n\t\t\tservice := decode(ev.Kv.Value)\n\t\t\tvar action string\n\n\t\t\tswitch ev.Type {\n\t\t\tcase clientv3.EventTypePut:\n\t\t\t\tif ev.IsCreate() {\n\t\t\t\t\taction = \"create\"\n\t\t\t\t} else if ev.IsModify() {\n\t\t\t\t\taction = \"update\"\n\t\t\t\t}\n\t\t\tcase clientv3.EventTypeDelete:\n\t\t\t\taction = \"delete\"\n\n\t\t\t\t// get service from prevKv\n\t\t\t\tservice = decode(ev.PrevKv.Value)\n\t\t\t}","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/micro/go-micro/blob/24529f140421a11a33b6999ab7944f2021cfd69c/registry/etcd/watcher.go#L34-L70","documentation":"etcdWatcher.Next() receives watch events over a channel. When the server sends a watch response marked Canceled (the watch was closed server-side, e.g. the watched lease expired or the watch was compacted/closed), Next returns 'could not get next' instead of a result.","triggerScenarios":"Iterating watcher.Next() while the underlying etcd watch is canceled — etcd returns wresp.Canceled=true (e.g. watch on a compacted revision, permission revoked, or server closing the watch) — and the code returns the error for that response.","commonSituations":"Long-running watchers surviving etcd cluster restarts or compaction; watching a service whose registration lease expired causing the watch to be torn down; auth token/permission changes mid-watch.","solutions":["Create a new watcher via registry.Watch() and resume watching when this error occurs","Check etcd server logs for compaction or permission errors that canceled the watch","Re-register the service / renew leases so the watched keys stay alive","Wrap Next in a loop that treats this error as a signal to reconnect rather than abort"],"exampleFix":"// before\nfor {\n  r, err := w.Next()\n  if err != nil { return err } // watcher dies permanently\n}\n// after\nfor {\n  r, err := w.Next()\n  if err != nil {\n    time.Sleep(time.Second)\n    w, err = registry.Watch() // recreate watcher and continue\n    continue\n  }\n  handle(r)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for {\n  r, err := w.Next()\n  if err != nil {\n    log.Printf(\"watch broken: %v; restarting\", err)\n    time.Sleep(backoff)\n    w = newWatcher() // recreate after cancellation\n    continue\n  }\n  handle(r)\n}","preventionTips":["Wrap watcher loops in reconnect-with-backoff logic","Monitor etcd for compaction and permission changes","Keep service leases renewed to avoid watch teardown"],"tags":["etcd","watcher","registry","network"],"backgroundTag":"watcher-canceled","analyzedSha":"24529f140421a11a33b6999ab7944f2021cfd69c","analyzedAt":"2026-09-01T02:52:24.923Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}