d2lang/d2 · error

cannot read a directory

Error message

cannot read a directory

What it means

MemoryFileHandle.Read returns this error when the handle refers to a directory in the in-memory filesystem. Directories have no byte content to read, so the Read fails immediately instead of returning garbage or EOF.

Source

Thrown at lib/memfs/memfs.go:63

type MemoryFileHandle struct {
	*MemoryFile
	offset int
}

func (mfs *MemoryFS) Open(name string) (fs.File, error) {
	file, ok := mfs.files[filepath.Clean(name)]
	if !ok {
		return nil, fs.ErrNotExist
	}
	return &MemoryFileHandle{MemoryFile: file}, nil
}

func (fh *MemoryFileHandle) Stat() (fs.FileInfo, error) { return fh.MemoryFile, nil }

func (fh *MemoryFileHandle) Read(b []byte) (int, error) {
	if fh.isDir {
		return 0, errors.New("cannot read a directory")
	}
	if fh.offset >= len(fh.content) {
		return 0, io.EOF
	}
	n := copy(b, fh.content[fh.offset:])
	fh.offset += n
	return n, nil
}

func (fh *MemoryFileHandle) Close() error { return nil }

func (mf *MemoryFile) Stat() (fs.FileInfo, error) { return mf, nil }
func (mf *MemoryFile) Read(b []byte) (int, error) {
	if mf.isDir {
		return 0, errors.New("cannot read a directory")
	}
	copy(b, mf.content)
	return len(mf.content), nil

View on GitHub (pinned to 0d69dca6f5)

Solutions

  1. Check entry.IsDir() (or Stat on the handle) before calling Read and use fs.ReadDir/ReadDirAll for directories
  2. Fix the path to point to a file
  3. Add a type-switch or stat check in the caller to branch between file reads and directory listings

Example fix

// before
fh, _ := mfs.Open("assets/")
n, err := fh.Read(buf)
// after
fi, _ := fh.Stat()
if fi.IsDir() {
    entries, err := mfs.ReadDir("assets/")
} else {
    n, err := fh.Read(buf)
}
Defensive patterns

Strategy: type-guard

Validate before calling

fi, err := mfs.Stat(path)
if err == nil && fi.IsDir() {
    // use ReadDir instead of Read
}

Type guard

func isFile(n fs.FileInfo) bool { return n != nil && !n.IsDir() }

Try / catch

n, err := fh.Read(buf)
if err != nil && err.Error() == "cannot read a directory" {
    entries, lerr := mfs.ReadDir(path)
    // handle directory listing
}

Prevention

When it happens

Trigger: Opening a directory entry from lib/memfs and calling Read on the resulting MemoryFileHandle; e.g. fh.Open on a path that is a directory, then fh.Read(buf).

Common situations: Walking a memfs tree and treating every entry as a file, using fs.ReadDir result incorrectly, or a path typo pointing at a directory instead of a file.

Related errors


AI-assisted analysis of d2lang/d2@0d69dca6f5 (2026-08-31). Data as JSON: /api/errors/34075fdf251a93d6. Report an issue: GitHub.