{"record":{"id":"408a0ea4b249f567","repo":"t8y2/dbx","slug":"root-znode-cannot-be-modified","errorCode":null,"errorMessage":"Root znode cannot be modified","messagePattern":"Root znode cannot be modified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/zookeeper/operations.go","lineNumber":100,"sourceCode":"\t\t\"found\":    true,\n\t\t\"key\":      path,\n\t\t\"value\":    encodeValue(data),\n\t\t\"metadata\": statMetadata(stat),\n\t}, nil\n}\n\nfunc (service *server) put(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 putRequest\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 modified\")\n\t}\n\tdata, err := decodeValue(request.Value)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\twriteMode := request.WriteMode\n\tif writeMode == \"\" {\n\t\twriteMode = \"upsert\"\n\t}\n\tswitch writeMode {\n\tcase \"create\":\n\t\treturn createNode(client, path, data, request.CreateMode)\n\tcase \"update\":\n\t\tstat, err := client.Set(path, data)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn putResult(stat), nil","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/zookeeper/operations.go#L82-L118","documentation":"put normalizes the request key into a znode path and refuses to write the root: if path == \"/\" it returns 'Root znode cannot be modified'. The ZooKeeper root znode is structural and this driver forbids creating/overwriting it, so keys that normalize to the root are rejected before any server call.","triggerScenarios":"Calling put (directly or via dispatch) with Key = \"/\" or an empty/blank key that normalizePath resolves to \"/\". Raised in agents/drivers/zookeeper/operations.go:100.","commonSituations":"Empty key field in a JSON put request; key built by string concatenation where the prefix variable was empty (\"\" + \"/\" remaining as \"/\"); users intending 'the namespace root' and passing \"/\"; path-join bugs trimming the actual node name.","solutions":["Provide a non-root key, e.g. \"/myapp/config\" instead of \"/\".","Guard your caller code to reject empty or \"/\" keys before invoking put.","Check how the key is assembled (prefix + name) — an unset prefix/name variable often collapses the path to \"/\".","Remember ZooKeeper namespaces are hierarchical: pick a dedicated parent znode for application data."],"exampleFix":"// before\nif key == \"\" { key = \"/\" }\nerr := driver.Put(ctx, key, value)\n// after\nif key == \"\" { return fmt.Errorf(\"key must not be empty\") }\nerr := driver.Put(ctx, \"/myapp/\"+key, value)","handlingStrategy":"validation","validationCode":"func validatePutKey(key string) error {\n    k := strings.TrimSpace(key)\n    if k == \"\" || k == \"/\" {\n        return errors.New(\"zookeeper put key must identify a non-root znode\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := validatePutKey(key); err != nil { return err }\n_, err := driver.Put(ctx, key, value)\nif err != nil && strings.Contains(err.Error(), \"Root znode cannot be modified\") {\n    return fmt.Errorf(\"refusing to write znode root; supply a child path: %w\", err)\n}","preventionTips":["Never default an empty key to \"/\"","Build keys with path.Join so prefixes cannot collapse to \"/\"","Reject empty key fields at the API/config boundary","Dedicate a namespace parent znode for application data"],"tags":["validation","zookeeper","znode","put"],"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-14T05:17:10.506Z"}