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

  1. Verify with os.Stat that the directory exists and is a directory immediately before the operation that walks it
  2. Fix ACLs, or run under an account that can read directory attributes
  3. Retry after the directory or share is available again
  4. 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

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


AI-assisted analysis of microsoft/typescript-go@1bcfa18d79 (2026-08-16). Data as JSON: /api/errors/b730185d5d1cf240. Report an issue: GitHub.