{"record":{"id":"86610cf20ce54063","repo":"vitessio/vitess","slug":"cannot-watch-directory-v-in-cell-v","errorCode":null,"errorMessage":"cannot watch directory %v in cell %v","messagePattern":"cannot watch directory (.+?) in cell (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"go/vt/topo/memorytopo/watch.go","lineNumber":50,"sourceCode":"\t}\n\n\tc.factory.Lock()\n\tdefer c.factory.Unlock()\n\n\tif c.factory.err != nil {\n\t\treturn nil, nil, c.factory.err\n\t}\n\tif err := c.factory.getOperationError(Watch, filePath); err != nil {\n\t\treturn nil, nil, err\n\t}\n\n\tn := c.factory.nodeByPath(c.cell, filePath)\n\tif n == nil {\n\t\treturn nil, nil, topo.NewError(topo.NoNode, filePath)\n\t}\n\tif n.contents == nil {\n\t\t// it's a directory\n\t\treturn nil, nil, fmt.Errorf(\"cannot watch directory %v in cell %v\", filePath, c.cell)\n\t}\n\tcurrent := &topo.WatchData{\n\t\tContents: n.contents,\n\t\tVersion:  NodeVersion(n.version),\n\t}\n\n\tnotifications := make(chan *topo.WatchData, 100)\n\twatchIndex := n.addWatch(watch{contents: notifications})\n\n\tgo func() {\n\t\t<-ctx.Done()\n\t\t// This function can be called at any point, so we first need\n\t\t// to make sure the watch is still valid.\n\t\tc.factory.Lock()\n\t\tdefer c.factory.Unlock()\n\n\t\tn := c.factory.nodeByPath(c.cell, filePath)\n\t\tif n == nil {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/vitessio/vitess/blob/01a25a7d176f94613b8d59d799f438380a8760e4/go/vt/topo/memorytopo/watch.go#L32-L68","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nchanges, cur, err := ts.Watch(ctx, cell, keyspacePath) // keyspacePath is a directory\n// after\nshardPath := path.Join(keyspacePath, shard)\nchanges, cur, err := ts.Watch(ctx, cell, shardPath)","handlingStrategy":"validation","validationCode":"// confirm the path is a leaf before watching\nif _, err := ts.Get(ctx, cell, watchPath); topo.IsErrType(err, topo.NoNode) {\n    children, _ := ts.List(ctx, cell, watchPath)\n    return fmt.Errorf(\"%s is a directory with children %v\", watchPath, children)\n}","typeGuard":"func isWatchDirectoryErr(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"cannot watch directory\")\n}","tryCatchPattern":"changes, cur, err := ts.Watch(ctx, cell, watchPath)\nif err != nil && strings.Contains(err.Error(), \"cannot watch directory\") {\n    return fmt.Errorf(\"fix watch path: %v\", err)\n}","preventionTips":["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"],"tags":["topo","memorytopo","watch","directory"],"backgroundTag":"topo-watch-directory-unsupported","analyzedSha":"01a25a7d176f94613b8d59d799f438380a8760e4","analyzedAt":"2026-09-01T17:28:30.605Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}