vitessio/vitess · error

cannot watch directory %v in cell %v

Error message

cannot watch directory %v in cell %v

What it means

memorytopo's Watch can only observe leaf nodes that hold contents. If the watched path resolves to a directory node (contents == nil, meaning it has children), Watch returns this error because directories cannot be watched for value changes in this implementation.

Source

Thrown at go/vt/topo/memorytopo/watch.go:50

	}

	c.factory.Lock()
	defer c.factory.Unlock()

	if c.factory.err != nil {
		return nil, nil, c.factory.err
	}
	if err := c.factory.getOperationError(Watch, filePath); err != nil {
		return nil, nil, err
	}

	n := c.factory.nodeByPath(c.cell, filePath)
	if n == nil {
		return nil, nil, topo.NewError(topo.NoNode, filePath)
	}
	if n.contents == nil {
		// it's a directory
		return nil, nil, fmt.Errorf("cannot watch directory %v in cell %v", filePath, c.cell)
	}
	current := &topo.WatchData{
		Contents: n.contents,
		Version:  NodeVersion(n.version),
	}

	notifications := make(chan *topo.WatchData, 100)
	watchIndex := n.addWatch(watch{contents: notifications})

	go func() {
		<-ctx.Done()
		// This function can be called at any point, so we first need
		// to make sure the watch is still valid.
		c.factory.Lock()
		defer c.factory.Unlock()

		n := c.factory.nodeByPath(c.cell, filePath)
		if n == nil {

View on GitHub (pinned to 01a25a7d17)

Solutions

  1. Verify the watched path refers to a leaf value node, not a parent with children
  2. Correct the path construction (e.g. append the final node component)
  3. List the parent path to confirm the expected child exists, then watch that child
  4. If you need directory-level notifications, poll with List or use a different topo backend

Example fix

// before
changes, cur, err := ts.Watch(ctx, cell, keyspacePath) // keyspacePath is a directory
// after
shardPath := path.Join(keyspacePath, shard)
changes, cur, err := ts.Watch(ctx, cell, shardPath)
Defensive patterns

Strategy: validation

Validate before calling

// confirm the path is a leaf before watching
if _, err := ts.Get(ctx, cell, watchPath); topo.IsErrType(err, topo.NoNode) {
    children, _ := ts.List(ctx, cell, watchPath)
    return fmt.Errorf("%s is a directory with children %v", watchPath, children)
}

Type guard

func isWatchDirectoryErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "cannot watch directory")
}

Try / catch

changes, cur, err := ts.Watch(ctx, cell, watchPath)
if err != nil && strings.Contains(err.Error(), "cannot watch directory") {
    return fmt.Errorf("fix watch path: %v", err)
}

Prevention

When it happens

Trigger: Calling topo.Server.Watch on a path that is a container (e.g. a keyspace or shard prefix) instead of a leaf node holding a serialized value; typo in the watch path pointing at a parent directory.

Common situations: Misconstructed path passed to Watch (missing the final leaf component such as the shard name or tablet file); using the file/memorytopo against a path layout where intermediate nodes are directories; tests seeding child nodes under the watched path.

Related errors


AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01). Data as JSON: /api/errors/86610cf20ce54063. Report an issue: GitHub.