charmbracelet/glow · error

unable to stat file: %w

Error message

unable to stat file: %w

What it means

The same validateStyle stat call, but for errors other than fs.ErrNotExist - the raw OS error is wrapped with %w. This means the style path could be located but stat-ing it failed: a parent directory lacks search permission (EACCES), a stale network mount (EIO), or the path exceeds limits (ENAMETOOLONG).

Source

Thrown at main.go:160

	if err != nil {
		return nil, fmt.Errorf("unable to open file: %w", err)
	}
	u, err := filepath.Abs(arg)
	if err != nil {
		return nil, fmt.Errorf("unable to get absolute path: %w", err)
	}
	return &source{r, u}, nil
}

// validateStyle checks if the style is a default style, if not, checks that
// the custom style exists.
func validateStyle(style string) error {
	if style != "auto" && styles.DefaultStyles[style] == nil {
		style = utils.ExpandPath(style)
		if _, err := os.Stat(style); errors.Is(err, fs.ErrNotExist) {
			return fmt.Errorf("specified style does not exist: %s", style)
		} else if err != nil {
			return fmt.Errorf("unable to stat file: %w", err)
		}
	}
	return nil
}

func validateOptions(cmd *cobra.Command) error {
	// grab config values from Viper
	width = viper.GetUint("width")
	mouse = viper.GetBool("mouse")
	pager = viper.GetBool("pager")
	tui = viper.GetBool("tui")
	showAllFiles = viper.GetBool("all")
	preserveNewLines = viper.GetBool("preserveNewLines")
	showLineNumbers = viper.GetBool("showLineNumbers")

	if pager && tui {
		return errors.New("cannot use both pager and tui")
	}

View on GitHub (pinned to e3970c813d)

Solutions

  1. Check traversability of each component: namei -l /path/to/style.json
  2. Repair or remount stale network mounts
  3. Shorten the path or move the style file to local disk
Defensive patterns

Strategy: try-catch

Validate before calling

func traversable(path string) error {
	for dir := path; dir != "/" && dir != "."; dir = filepath.Dir(dir) {
		if _, err := os.Stat(dir); err != nil { return fmt.Errorf("%s: %w", dir, err) }
	}
	return nil
}

Type guard

func isPermissionErr(err error) bool { return errors.Is(err, fs.ErrPermission) }

Try / catch

if _, err := os.Stat(stylePath); err != nil {
	switch {
	case errors.Is(err, fs.ErrNotExist):
		// style file missing: use a built-in style
	case errors.Is(err, fs.ErrPermission):
		// parent traversal denied: report the offending dir
	default:
		// I/O or path-length error: surface the wrapped error
	}
}

Prevention

When it happens

Trigger: A parent directory in the style path is not traversable by the user; the style file sits on a stale NFS/fuse mount; the path is longer than PATH_MAX.

Common situations: Styles kept on network home directories that went stale, restricted multi-user machines, deeply nested config directories exceeding path limits.

Related errors


AI-assisted analysis of charmbracelet/glow@e3970c813d (2026-08-15). Data as JSON: /api/errors/191d7e666ddb1388. Report an issue: GitHub.