charmbracelet/glow · error · errMsg

could not load file: missing path

Error message

could not load file: missing path

What it means

loadLocalMarkdown is a bubbletea Cmd used by the stash/pager to read a document from disk into md.Body. If the markdown struct's localPath is the empty string, there is nothing to os.ReadFile, so it immediately returns this errMsg. Documents that come from the network or are constructed without a path have localPath == "".

Source

Thrown at ui/stash.go:844

	if itemsOnPage < m.paginator().PerPage {
		n := (m.paginator().PerPage - itemsOnPage) * stashViewItemHeight
		if len(mds) == 0 {
			n -= stashViewItemHeight - 1
		}
		for i := 0; i < n; i++ {
			fmt.Fprint(&b, "\n")
		}
	}

	return b.String()
}

// COMMANDS

func loadLocalMarkdown(md *markdown) tea.Cmd {
	return func() tea.Msg {
		if md.localPath == "" {
			return errMsg{errors.New("could not load file: missing path")}
		}

		data, err := os.ReadFile(md.localPath)
		if err != nil {
			log.Debug("error reading local file", "error", err)
			return errMsg{err}
		}
		md.Body = string(data)
		return fetchedMarkdownMsg(md)
	}
}

func filterMarkdowns(m stashModel) tea.Cmd {
	return func() tea.Msg {
		if m.filterInput.Value() == "" || !m.filterApplied() {
			return filteredMarkdownMsg(m.markdowns) // return everything
		}

View on GitHub (pinned to e3970c813d)

Solutions

  1. Open the document from the local filesystem (file picker or glow <path>) so localPath is populated
  2. For remote/stashed docs, use the fetch-from-stash command path instead of the local loader
  3. If embedding glow's UI, always construct markdown with a non-empty localPath before triggering a reload

Example fix

// ui/ui.go — local documents get a path
md := &markdown{localPath: path}

// before (path missing)
md := &markdown{}
cmd := loadLocalMarkdown(md) // errMsg: could not load file: missing path

// after
md := &markdown{localPath: "/tmp/errlookup-LwPSGd/README.md"}
cmd := loadLocalMarkdown(md)
Defensive patterns

Strategy: type-guard

Validate before calling

// before issuing loadLocalMarkdown, make sure a path exists
if md.localPath == "" {
	md.localPath = pickFileWithPicker() // or refuse the action
	if md.localPath == "" {
		return nil // do not dispatch the load command at all
	}
}

Type guard

// hasLocalSource reports whether md can be loaded from disk
// (ui/markdown.go keeps the path in the unexported localPath field).
func hasLocalSource(md *markdown) bool {
	return md != nil && md.localPath != ""
}

if !hasLocalSource(md) {
	return tea.Quit // or route to the network fetch command instead
}
cmd := loadLocalMarkdown(md)

Try / catch

// errMsg arrives as a tea.Msg in Update:
switch msg := msg.(type) {
case errMsg:
	if strings.Contains(msg.err.Error(), "missing path") {
		// document has no backing file; refresh state or switch source
		return m, fetchFromStashCmd(m.currentDocument)
	}
	m.err = msg
	return m, tea.Quit
}

Prevention

When it happens

Trigger: Opening a markdown item in the TUI whose localPath was never set (e.g., a news/stash item fetched from the network rather than a local file); a document struct built with only a URL; triggering a reload (pager key or file-watch event) after the path field was lost.

Common situations: Using the stash UI on remote/Glow-hosted docs and hitting the local-load path; opening the pager on a doc created from stdin where no filename exists; stale state after a failed load.

Related errors


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