{"record":{"id":"ce4500056ad2b6bc","repo":"t8y2/dbx","slug":"root-znode-cannot-be-deleted","errorCode":null,"errorMessage":"Root znode cannot be deleted","messagePattern":"Root znode cannot be deleted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/zookeeper/operations.go","lineNumber":217,"sourceCode":"\t\tif _, err := client.Create(current, nil, 0); err != nil && err != zk.ErrNodeExists {\n\t\t\treturn err\n\t\t}\n\t}\n\treturn nil\n}\n\nfunc (service *server) delete(params json.RawMessage) (map[string]any, error) {\n\tclient, err := service.requireClient()\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tvar request deleteRequest\n\tif err := json.Unmarshal(params, &request); err != nil {\n\t\treturn nil, err\n\t}\n\tpath := normalizePath(request.Key)\n\tif path == \"/\" {\n\t\treturn nil, errors.New(\"Root znode cannot be deleted\")\n\t}\n\texists, _, err := client.Exists(path)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tif !exists {\n\t\treturn map[string]any{\"deleted\": 0}, nil\n\t}\n\tif !request.Recursive {\n\t\tif err := client.Delete(path); err != nil {\n\t\t\tif err == zk.ErrNoNode {\n\t\t\t\treturn map[string]any{\"deleted\": 0}, nil\n\t\t\t}\n\t\t\treturn nil, err\n\t\t}\n\t\treturn map[string]any{\"deleted\": 1}, nil\n\t}\n\tdeleted, err := deleteSubtree(client, path)","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/zookeeper/operations.go#L199-L235","documentation":"delete normalizes the request key into a znode path and refuses to delete the root: if path == \"/\" it returns 'Root znode cannot be deleted'. Deleting / would be destructive/invalid, so the driver rejects it before touching the server.","triggerScenarios":"Calling delete (directly or via dispatch) with Key = \"/\" or an empty key that normalizePath maps to \"/\". Raised in agents/drivers/zookeeper/operations.go:217.","commonSituations":"Recursive-delete helper that started at the root; an empty key after trimming in caller code; a 'clear namespace' feature that mistakenly targets \"/\"; path-building bugs where the namespace prefix was lost.","solutions":["Pass a specific child path, e.g. \"/myapp/config\", never \"/\".","Add caller-side validation rejecting empty or \"/\" keys before delete.","If you intended to wipe an application subtree, delete that subtree's parent znode instead of the root.","Review recursive cleanup loops to ensure they never start at \"/\"."],"exampleFix":"// before\ndriver.Delete(ctx, \"/\") // rejected\n// after\ndriver.Delete(ctx, \"/myapp/tmp-node\")","handlingStrategy":"validation","validationCode":"func validateDeleteKey(key string) error {\n    k := strings.TrimSpace(key)\n    if k == \"\" || k == \"/\" {\n        return errors.New(\"zookeeper delete key must identify a non-root znode\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := validateDeleteKey(key); err != nil { return err }\nerr := driver.Delete(ctx, key)\nif err != nil && strings.Contains(err.Error(), \"Root znode cannot be deleted\") {\n    return fmt.Errorf(\"refusing to delete znode root: %w\", err)\n}","preventionTips":["Never start recursive cleanup at \"/\"","Reject empty or \"/\" keys before calling delete","Scope deletes under an application namespace prefix","Code-review any 'purge'/'clear' feature for root-path handling"],"tags":["validation","zookeeper","znode","delete"],"backgroundTag":"invalid-key-path","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"}