{"record":{"id":"0d6e9c0c5dba2076","repo":"t8y2/dbx","slug":"etcd-watch-scope-invalid-0d6e9c","errorCode":"ETCD_WATCH_SCOPE_INVALID","errorMessage":"ETCD_WATCH_SCOPE_INVALID: scope must be key or prefix","messagePattern":"ETCD_WATCH_SCOPE_INVALID: scope must be key or prefix","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/etcd2-go/watch.go","lineNumber":222,"sourceCode":"func (s *etcd2Session) removeWatch(id string) *watchState {\n\ts.watchesMu.Lock()\n\tdefer s.watchesMu.Unlock()\n\tstate := s.watches[id]\n\tdelete(s.watches, id)\n\treturn state\n}\n\nfunc (s *etcd2Session) watchStart(params map[string]json.RawMessage) (any, error) {\n\tif s.watchCount() >= maxWatches {\n\t\treturn nil, fmt.Errorf(\"ETCD_WATCH_LIMIT: at most %d watches are allowed per connection\", maxWatches)\n\t}\n\tkey, err := keyBytesParam(params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tscope := stringOrDefault(params, \"scope\", \"key\")\n\tif scope != \"key\" && scope != \"prefix\" {\n\t\treturn nil, errors.New(\"ETCD_WATCH_SCOPE_INVALID: scope must be key or prefix\")\n\t}\n\tclient, err := s.activeClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// startRevision maps to the v2 waitIndex: default to the current index+1.\n\trequestedRevision := longOrNull(params, \"startRevision\")\n\tvar waitIndex int64\n\tif requestedRevision != nil && *requestedRevision > 0 {\n\t\twaitIndex = *requestedRevision\n\t} else {\n\t\tcurrent, err := client.currentEtcdIndex()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\twaitIndex = current + 1\n\t}","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/etcd2-go/watch.go#L204-L240","documentation":"This error is thrown by the etcd2 driver's watchStart when the caller supplies a 'scope' parameter that is neither 'key' nor 'prefix'. Watches in etcd are limited to either an exact key or a key prefix, so any other scope value is rejected before a client is even opened. It is a fail-fast input validation for the watch API.","triggerScenarios":"Calling the watch op with params {\"key\": \"...\", \"scope\": \"keys\"} or any misspelled value like \"Key\", \"prefixes\", or \"dir\"; omitting validation of scope before passing user-supplied params through.","commonSituations":"Typo in the scope string, dynamically building watch parameters from config or query strings where the scope comes from an unvalidated field, or porting code from another etcd library that uses different scope vocabulary (e.g. 'range').","solutions":["Change the scope parameter to exactly \"key\" or \"prefix\" (case-sensitive, lowercase).","If scope is omitted, the default is \"key\", so drop the parameter entirely for exact-key watches.","Validate user/config-supplied scope against an allowlist before calling watch.","For watching a range that is not a prefix, issue multiple prefix watches or filter results client-side with a key watch plus filtering."],"exampleFix":"// before\nparams := map[string]any{\"key\": \"/cfg/app\", \"scope\": \"subtree\"}\n// after\nparams := map[string]any{\"key\": \"/cfg/app\", \"scope\": \"prefix\"}","handlingStrategy":"validation","validationCode":"func validScope(p map[string]any) error {\n    s, _ := p[\"scope\"].(string)\n    if s != \"\" && s != \"key\" && s != \"prefix\" {\n        return fmt.Errorf(\"scope %q must be \\\"key\\\" or \\\"prefix\\\"\", s)\n    }\n    return nil\n}","typeGuard":"func isWatchScope(s string) bool { return s == \"key\" || s == \"prefix\" }","tryCatchPattern":null,"preventionTips":["Keep a constants list of allowed scope values (\"key\", \"prefix\") and use them, never raw strings","Validate watch params centrally before any watch call","Remember scope defaults to \"key\" when omitted"],"tags":["etcd","watch","validation","parameters"],"backgroundTag":"invalid-parameter-value","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}