gastownhall/beads · error

failed to open file: %w

Error message

failed to open file: %w

What it means

parseMarkdownFile opens the validated path with os.Open; any open failure (permission denied, file vanished between validation and open, I/O error) is wrapped as "failed to open file: <os error>". This happens after path validation succeeded, so it usually reflects transient or permission issues rather than a missing file.

Source

Thrown at cmd/bd/markdown.go:271

	scanner := bufio.NewScanner(file)
	// Increase buffer size for large markdown files
	const maxScannerBuffer = 1024 * 1024 // 1MB
	buf := make([]byte, maxScannerBuffer)
	scanner.Buffer(buf, maxScannerBuffer)
	return scanner
}

func parseMarkdownFile(path string) ([]*IssueTemplate, error) {
	// Validate and clean the file path
	cleanPath, err := validateMarkdownPath(path)
	if err != nil {
		return nil, err
	}

	// #nosec G304 -- Path is validated by validateMarkdownPath which prevents traversal
	file, err := os.Open(cleanPath)
	if err != nil {
		return nil, fmt.Errorf("failed to open file: %w", err)
	}
	defer func() {
		_ = file.Close() // Close errors on read-only operations are not actionable
	}()

	state := &markdownParseState{}
	scanner := createMarkdownScanner(file)

	for scanner.Scan() {
		line := scanner.Text()

		// Check for H2 (new issue)
		if matches := h2Regex.FindStringSubmatch(line); matches != nil {
			state.handleH2Header(matches)
			continue
		}

		// Check for H3 (section within issue)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check file readability: `ls -l <file>` and `test -r <file>`; fix with chmod/chown or run as a user with access
  2. Re-run the command — the file may have been deleted mid-run by a prior step
  3. Verify the file is a regular readable file (not a broken symlink): `readlink -f <file>`
  4. Check mount health if the file is on NFS/network storage

Example fix

# before (unreadable file)
-rw------- issues.md  owned by root, bd runs as app user
# after
chmod 644 issues.md  # or chown app:app issues.md
Defensive patterns

Strategy: try-catch

Validate before calling

f, err := os.Open(path)
if err != nil {
	return fmt.Errorf("pre-flight open failed: %w", err)
}
f.Close()

Try / catch

if err := runImport(path); err != nil {
	var pe *fs.PathError
	if errors.As(err, &pe) && errors.Is(pe.Err, os.ErrPermission) {
		// fix permissions or run as another user, then retry once
	} else {
		return err
	}
}

Prevention

When it happens

Trigger: os.Open fails on an already-validated .md path: file deleted in a race between Stat and Open, read permission denied, or underlying device/I/O error (e.g. broken symlink surviving Stat, NFS stale handle).

Common situations: Files on network mounts going stale; another process deleting the temp file mid-run; restrictive umask/ownership after generation; container user lacking read access to mounted volume.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/c8ffbaf05e56563b. Report an issue: GitHub.