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
- Verify the watched path refers to a leaf value node, not a parent with children
- Correct the path construction (e.g. append the final node component)
- List the parent path to confirm the expected child exists, then watch that child
- 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
- Build watch paths with the full leaf component (e.g. path.Join(keyspace, shard))
- Sanity-check paths by listing the parent before watching
- Remember memorytopo/file-based topos distinguish directories from leaf values
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
- delete(%v, %v) failed: it's a directory
- node %v is not locked
- watch on %v was closed
- watch terminated with no error
- there are no cells in the topo
AI-assisted analysis of vitessio/vitess@01a25a7d17 (2026-09-01).
Data as JSON: /api/errors/86610cf20ce54063.
Report an issue: GitHub.