micro-editor/micro · error
Error: %s is not a regular file and cannot be opened
Error message
Error: %s is not a regular file and cannot be opened
What it means
Returned by the same buffer constructor (internal/buffer/buffer.go:300) when os.Stat succeeds, the target is not a directory, but Mode().IsRegular() is false — i.e. character/block devices, FIFOs, Unix sockets and similar special files. Only regular files (or nonexistent paths, which create empty buffers) are openable; anything else is rejected with the path in the message.
Source
Thrown at internal/buffer/buffer.go:300
if err != nil {
cmd.StartCursor = Loc{-1, -1}
}
}
filename, err = util.ReplaceHome(filename)
if err != nil {
return nil, err
}
fileInfo, serr := os.Stat(filename)
if serr != nil && !errors.Is(serr, fs.ErrNotExist) {
return nil, serr
}
if serr == nil && fileInfo.IsDir() {
return nil, errors.New("Error: " + filename + " is a directory and cannot be opened")
}
if serr == nil && !fileInfo.Mode().IsRegular() {
return nil, errors.New("Error: " + filename + " is not a regular file and cannot be opened")
}
f, err := os.OpenFile(filename, os.O_WRONLY, 0)
readonly := errors.Is(err, fs.ErrPermission)
f.Close()
file, err := os.Open(filename)
if err == nil {
defer file.Close()
}
var buf *Buffer
if errors.Is(err, fs.ErrNotExist) {
// File does not exist -- create an empty buffer with that name
buf = NewBufferFromString("", filename, btype)
} else if err != nil {
return nil, err
} else {View on GitHub (pinned to 1c8b82b32e)
Solutions
- For stream-like sources, pipe instead: dmesg | micro (micro reads stdin when it's not a tty)
- Open the backing regular file, not the device node
- In code, require fi.Mode().IsRegular() before calling NewBufferFromFile (see validation snippet)
Example fix
// before micro /dev/ttyUSB0 # Error: /dev/ttyUSB0 is not a regular file and cannot be opened // after cat /dev/ttyUSB0 | micro
Defensive patterns
Strategy: validation
Validate before calling
// Only regular files (or missing paths) reach NewBufferFromFile
func isRegularOrMissing(path string) bool {
fi, err := os.Stat(path)
if err != nil { return true } // new buffer will be created
return fi.Mode().IsRegular()
}
if !isRegularOrMissing(p) { return fmt.Errorf("%s is a special file", p) } Try / catch
buf, err := buffer.NewBufferFromFile(path, buffer.BTDefault)
if err != nil {
if strings.HasSuffix(err.Error(), "is not a regular file and cannot be opened") {
// devices/fifos: redirect users to piping
InfoBar.Error(err.Error() + " — pipe instead: cmd | micro")
return nil
}
return nil, err
} Prevention
- Use 'producer | micro' for streams instead of opening /dev nodes
- For /proc and /sys views, copy to a temp file first
- Audit scripts that feed globbed paths to micro so device entries are filtered
When it happens
Trigger: micro /dev/null, /dev/video0, /dev/tty, a named pipe created by mkfifo, or a unix socket file; :open /dev/urandom style probes.
Common situations: Trying to view device output in-editor ('micro /dev/ttyUSB0'); opening /dev/stdin or /dev/fd/N special files instead of piping (which micro supports via stdin: `cmd | micro`); container setups where a config path is a mounted socket.
Related errors
- Error: %s is a directory and cannot be opened
- could not open file
- Error: %s is a directory and cannot be saved
- Error: %s is not a regular file and cannot be saved
- Error reading bindings.json file: %s
AI-assisted analysis of micro-editor/micro@1c8b82b32e (2026-08-15).
Data as JSON: /api/errors/0fbc8b97387cfd7e.
Report an issue: GitHub.