microsoft/typescript-go · error
error opening directory: %w
Error message
error opening directory: %w
What it means
Returned by the Windows implementation of walkDir, the tree-enumeration helper used when watch setup must list a directory tree before arming OS watches. GetFileAttributesEx on the walk root failed, and the message wraps the Win32 error (ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND, ERROR_ACCESS_DENIED, and similar). The primary Windows watcher itself uses ReadDirectoryChangesW and does not walk, so this surfaces from walk-driven setup paths and tests that exercise the walker.
Source
Thrown at internal/fswatch/walkdir_windows.go:21
package fswatch
import (
"fmt"
"syscall"
"unsafe"
"golang.org/x/sys/windows"
)
// walkDir walks a directory tree on Windows using FindFirstFile/FindNextFile.
func walkDir(dir string, recursive bool, fn func(path string, isDir bool) error) error {
rootPtr, err := windows.UTF16PtrFromString(dir)
if err != nil {
return err
}
var rootData windows.Win32FileAttributeData
if err := windows.GetFileAttributesEx(rootPtr, windows.GetFileExInfoStandard, (*byte)(unsafe.Pointer(&rootData))); err != nil {
return fmt.Errorf("error opening directory: %w", err)
}
if rootData.FileAttributes&windows.FILE_ATTRIBUTE_DIRECTORY == 0 ||
rootData.FileAttributes&windows.FILE_ATTRIBUTE_REPARSE_POINT != 0 {
return syscall.ENOTDIR
}
if fn != nil {
if err := fn(dir, true); err != nil {
return err
}
}
stack := []string{dir}
for len(stack) > 0 {
path := stack[len(stack)-1]
stack = stack[:len(stack)-1]
spec := path + "\\*"
specPtr, err := windows.UTF16PtrFromString(spec)View on GitHub (pinned to 1bcfa18d79)
Solutions
- Verify with os.Stat that the directory exists and is a directory immediately before the operation that walks it
- Fix ACLs, or run under an account that can read directory attributes
- Retry after the directory or share is available again
- Keep the walked root stable for the duration of the walk; coordinate with cleanup jobs
Example fix
// before
err := walkDir(root, true, visit)
// after
info, err := os.Stat(root)
if err != nil {
return err
}
if !info.IsDir() {
return fmt.Errorf("not a directory: %s", root)
}
err = walkDir(root, true, visit) Defensive patterns
Strategy: validation
Validate before calling
info, err := os.Stat(dir)
if err != nil {
return err
}
if !info.IsDir() {
return syscall.ENOTDIR
} Try / catch
err := walkDrivenSetup(dir)
if err != nil {
if errors.Is(err, windows.ERROR_PATH_NOT_FOUND) || errors.Is(err, windows.ERROR_FILE_NOT_FOUND) {
// directory vanished: verify and retry
}
if errors.Is(err, windows.ERROR_ACCESS_DENIED) {
// fix ACLs or account
}
} Prevention
- Validate existence and type right before any tree walk
- Keep walked roots alive for the walk duration; coordinate with cleanup jobs
- Run under accounts with read access to the target tree
- Retry around transient share outages instead of failing permanently
When it happens
Trigger: walkDir runs against a directory that no longer exists, was deleted between the caller's existence check and the walk, sits on an unavailable network share, or denies attribute reads to the process. A path containing an embedded NUL fails earlier in UTF16PtrFromString and returns that error instead.
Common situations: Tree walks over UNC paths (\\server\share) when the share drops mid-operation. Directories removed by a concurrent build step. Locked-down ACLs on system directories.
Related errors
- error watching %s: %w
- could not get file information
- GetOverlappedResult failed
- invalid handle: %w
- failed to create profile directory: %w
AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16).
Data as JSON: /api/errors/b730185d5d1cf240.
Report an issue: GitHub.