{"record":{"id":"620475137e89e3f0","repo":"t8y2/dbx","slug":"etcd-v2-unsupported","errorCode":"ETCD_V2_UNSUPPORTED","errorMessage":"ETCD_V2_UNSUPPORTED: %s is not available on the etcd v2 API","messagePattern":"ETCD_V2_UNSUPPORTED: (.+?) is not available on the etcd v2 API","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/etcd2-go/main.go","lineNumber":388,"sourceCode":"\tcase \"etcd_auth_role_get\":\n\t\treturn s.authRoleGet(params)\n\tcase \"etcd_auth_role_add\":\n\t\treturn s.authRoleAdd(params)\n\tcase \"etcd_auth_role_delete\":\n\t\treturn s.authRoleDelete(params)\n\tcase \"etcd_auth_role_grant_permission\":\n\t\treturn s.authRolePermission(params, true)\n\tcase \"etcd_auth_role_revoke_permission\":\n\t\treturn s.authRolePermission(params, false)\n\tcase \"disconnect\":\n\t\ts.close()\n\t\treturn map[string]bool{\"ok\": true}, nil\n\tcase \"shutdown\":\n\t\ts.close()\n\t\treturn map[string]bool{\"ok\": true}, nil\n\tdefault:\n\t\tif isEtcd3OnlyMethod(method) {\n\t\t\treturn nil, fmt.Errorf(\"ETCD_V2_UNSUPPORTED: %s is not available on the etcd v2 API\", method)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"unknown method: %s\", method)\n\t}\n}\n\nfunc isEtcd3OnlyMethod(method string) bool {\n\tswitch method {\n\tcase \"kv_history\", \"etcd_compact\", \"etcd_defrag\",\n\t\t\"etcd_lease_list\", \"etcd_lease_get\", \"etcd_lease_grant\",\n\t\t\"etcd_lease_keepalive_once\", \"etcd_lease_revoke\":\n\t\treturn true\n\t}\n\treturn false\n}\n\nfunc decodeParams(params map[string]json.RawMessage, target any) error {\n\tif params == nil {\n\t\tparams = map[string]json.RawMessage{}","sourceCodeStart":370,"sourceCodeEnd":406,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/etcd2-go/main.go#L370-L406","documentation":"The v2 runtime's handle() dispatch checks isEtcd3OnlyMethod and rejects methods that exist only in etcd's v3 API (e.g. kv_history, etcd_compact, etcd_defrag, watches, leases) with this coded error. The v2 driver cannot emulate those primitives, so it fails explicitly instead of silently misbehaving.","triggerScenarios":"Sending an etcd3-only method name (per isEtcd3OnlyMethod's switch list) to the etcd2 driver's handle(), e.g. calling etcd_compact or kv_history through the v2 agent.","commonSituations":"Shared client code written against an etcd3 driver pointed at the v2 driver, feature-detection missing, tests like TestEtcd3OnlyMethodsRejected exercising the rejection path.","solutions":["Use the etcd3 (gRPC) driver for methods requiring v3 semantics.","Gate the call behind a capability check (isEtcd3OnlyMethod or equivalent) before dispatch.","Rework the operation using v2 primitives where possible (e.g. poll keys instead of watch)."],"exampleFix":"// before\nhandle(v2Session, \"etcd_defrag\", {})\n// after\nif !isEtcd3OnlyMethod(\"etcd_defrag\") { handle(v2Session, \"etcd_defrag\", {}) } // or use the v3 driver","handlingStrategy":"validation","validationCode":"if isEtcd3OnlyMethod(method) { return fmt.Errorf(\"method %s requires the etcd3 driver; v2 driver in use\", method) }","typeGuard":"func v2Capable(method string) bool { return !isEtcd3OnlyMethod(method) }","tryCatchPattern":"if err := handle(session, method, params); err != nil && strings.Contains(err.Error(), \"ETCD_V2_UNSUPPORTED\") {\n    return routeToV3Driver(session, method, params)\n}","preventionTips":["Feature-detect the driver (v2 vs v3) before dispatch","Centralize method routing in one place that knows v2 limitations","Read isEtcd3OnlyMethod's list when adding new callers"],"tags":["etcd","api-compatibility","unsupported-method"],"backgroundTag":"unsupported-api-version","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"}