t8y2/dbx · error

Root znode cannot be deleted

Error message

Root znode cannot be deleted

What it means

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.

Source

Thrown at agents/drivers/zookeeper/operations.go:217

		if _, err := client.Create(current, nil, 0); err != nil && err != zk.ErrNodeExists {
			return err
		}
	}
	return nil
}

func (service *server) delete(params json.RawMessage) (map[string]any, error) {
	client, err := service.requireClient()
	if err != nil {
		return nil, err
	}
	var request deleteRequest
	if err := json.Unmarshal(params, &request); err != nil {
		return nil, err
	}
	path := normalizePath(request.Key)
	if path == "/" {
		return nil, errors.New("Root znode cannot be deleted")
	}
	exists, _, err := client.Exists(path)
	if err != nil {
		return nil, err
	}
	if !exists {
		return map[string]any{"deleted": 0}, nil
	}
	if !request.Recursive {
		if err := client.Delete(path); err != nil {
			if err == zk.ErrNoNode {
				return map[string]any{"deleted": 0}, nil
			}
			return nil, err
		}
		return map[string]any{"deleted": 1}, nil
	}
	deleted, err := deleteSubtree(client, path)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Pass a specific child path, e.g. "/myapp/config", never "/".
  2. Add caller-side validation rejecting empty or "/" keys before delete.
  3. If you intended to wipe an application subtree, delete that subtree's parent znode instead of the root.
  4. Review recursive cleanup loops to ensure they never start at "/".

Example fix

// before
driver.Delete(ctx, "/") // rejected
// after
driver.Delete(ctx, "/myapp/tmp-node")
Defensive patterns

Strategy: validation

Validate before calling

func validateDeleteKey(key string) error {
    k := strings.TrimSpace(key)
    if k == "" || k == "/" {
        return errors.New("zookeeper delete key must identify a non-root znode")
    }
    return nil
}

Try / catch

if err := validateDeleteKey(key); err != nil { return err }
err := driver.Delete(ctx, key)
if err != nil && strings.Contains(err.Error(), "Root znode cannot be deleted") {
    return fmt.Errorf("refusing to delete znode root: %w", err)
}

Prevention

When it happens

Trigger: Calling delete (directly or via dispatch) with Key = "/" or an empty key that normalizePath maps to "/". Raised in agents/drivers/zookeeper/operations.go:217.

Common situations: 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.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/ce4500056ad2b6bc. Report an issue: GitHub.