{"record":{"id":"93043dac47905b75","repo":"t8y2/dbx","slug":"etcd-newkey-required-93043d","errorCode":"ETCD_NEWKEY_REQUIRED","errorMessage":"ETCD_NEWKEY_REQUIRED","messagePattern":"ETCD_NEWKEY_REQUIRED","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/etcd2-go/kv.go","lineNumber":297,"sourceCode":"\t}\n\treturn map[string]any{\"deleted\": int64(1), \"revision\": longString(revision)}, nil\n}\n\n// rename is a non-atomic check-then-set: the v2 API has no transactions, so a\n// concurrent writer between the target check and the delete can be lost. The\n// protocol exposes this honestly instead of pretending atomicity.\nfunc (s *etcd2Session) rename(params map[string]json.RawMessage) (any, error) {\n\tclient, err := s.activeClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tsourceKey, err := keyBytesParam(params)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnewKey := stringOrNull(params, \"newKey\")\n\tif newKey == nil || *newKey == \"\" {\n\t\treturn nil, errors.New(\"ETCD_NEWKEY_REQUIRED\")\n\t}\n\ttargetKey := *newKey\n\tif sourceKey == targetKey {\n\t\treturn map[string]any{\"renamed\": true, \"revision\": nil}, nil\n\t}\n\n\tctx, cancel := s.beginOperation()\n\tdefer s.endOperation(cancel)\n\tbody, _, err := client.do(ctx, http.MethodGet, v2KeyPath(sourceKey), \"\", nil)\n\tif err != nil {\n\t\tif isNotFound(err) {\n\t\t\treturn nil, errors.New(\"ETCD_NOT_FOUND: source key does not exist\")\n\t\t}\n\t\treturn nil, err\n\t}\n\tvar source v2KeysResponse\n\tif err := json.Unmarshal(body, &source); err != nil {\n\t\treturn nil, err","sourceCodeStart":279,"sourceCodeEnd":315,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/etcd2-go/kv.go#L279-L315","documentation":"rename requires a target key name in the newKey parameter. The driver validates this before touching etcd and fails fast with this sentinel error when newKey is absent or an empty string. No etcd request is made.","triggerScenarios":"Calling the rename operation without a newKey field, with newKey: null, or with newKey: \"\" in the params map.","commonSituations":"A caller copied a put/get params object that only has key/value and forgot to add newKey; a UI or config layer dropped the empty target field; a generic dispatcher forwards user JSON where newKey was never provided.","solutions":["Pass a non-empty newKey string in the rename params, e.g. {\"key\":\"old\",\"newKey\":\"new\"}.","Validate newKey at the call site before invoking rename.","If you intended a no-op, note rename with source==target returns {renamed:true}; an empty target is still rejected, so guard empty strings upstream."],"exampleFix":"// before\nres, err := agent.Handle(ctx, \"rename\", map[string]any{\"key\": \"old-key\"})\n// after\nres, err := agent.Handle(ctx, \"rename\", map[string]any{\"key\": \"old-key\", \"newKey\": \"new-key\"})","handlingStrategy":"validation","validationCode":"newKey, ok := params[\"newKey\"].(string)\nif !ok || newKey == \"\" {\n    return errors.New(\"rename requires a non-empty newKey\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := agent.Handle(ctx, \"rename\", params); err != nil && strings.Contains(err.Error(), \"ETCD_NEWKEY_REQUIRED\") {\n    // fix params and re-dispatch with a valid newKey\n}","preventionTips":["Validate required params (key, newKey) before every rename call","Reject empty strings, not just absent fields — the driver treats \"\" as missing","Centralize param construction in a typed builder so fields cannot be dropped","Add unit tests covering rename with missing/empty newKey"],"tags":["etcd","validation","missing-parameter","rename"],"backgroundTag":"missing-required-parameter","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}