gastownhall/beads · error

failed to read file: %w

Error message

failed to read file: %w

What it means

readBodyFile wraps io.ReadAll failures with this error: the file (or stdin pipe) was opened successfully but reading its contents failed. This is rarer than open failures and typically indicates I/O problems — a failing disk, a broken pipe on stdin, or reading a special/character device that errors mid-read.

Source

Thrown at cmd/bd/flags.go:206

// If filePath is "-", reads from stdin.
func readBodyFile(filePath string) (string, error) {
	var reader io.Reader

	if filePath == "-" {
		reader = os.Stdin
	} else {
		// #nosec G304 - filePath comes from user flag, validated by caller
		file, err := os.Open(filePath)
		if err != nil {
			return "", fmt.Errorf("failed to open file: %w", err)
		}
		defer file.Close()
		reader = file
	}

	content, err := io.ReadAll(reader)
	if err != nil {
		return "", fmt.Errorf("failed to read file: %w", err)
	}

	return string(content), nil
}

// textSources names the places a command can take body text from: stdin, a
// file path, an explicit text flag, then positional args. A non-nil stdin
// means --stdin was given. flagName names the text flag (e.g. "--response")
// in conflict errors and always accompanies flagText. flagSet marks the text
// flag as explicitly passed (cobra's Changed), so an empty flag value still
// counts as a source — like a blank positional — rather than as absent.
type textSources struct {
	stdin      io.Reader
	filePath   string
	flagText   string
	flagName   string
	flagSet    bool
	positional []string

View on GitHub (pinned to 71377f2769)

Solutions

  1. If using '-' with a pipe, check that the upstream command completed successfully (its exit status) and re-run the pipeline
  2. Retry reading the file with cat <path> to confirm the file itself is readable; check dmesg/disk health if reads fail system-wide
  3. Copy the file to local disk if it lives on a flaky network mount, then retry the bd command
  4. Pass the content inline or via an editor instead of a file if the source is unreliable

Example fix

// before: upstream failure silently truncates the pipe
./gen-notes | bd update bd-1 --description-file=-   // failed to read file: read ...: broken pipe
// after: propagate upstream failure before feeding bd
notes=$(./gen-notes) && printf '%s' "$notes" | bd update bd-1 --description-file=-
Defensive patterns

Strategy: try-catch

Validate before calling

path := filePath
if path != "-" {
    if _, err := os.ReadFile(path); err != nil {
        return fmt.Errorf("body file not readable: %w", err)
    }
}

Try / catch

content, err := readBodyFile(flagPath)
if err != nil {
    var perr *os.PathError
    if errors.As(err, &perr) {
        return fmt.Errorf("reading body %s: %v", flagPath, perr.Err)
    }
    return err
}

Prevention

When it happens

Trigger: Passing a file flag pointing at a special file (e.g. /dev files) that errors on read; disk or network filesystem failure mid-read; stdin ('-') receiving a broken pipe or being closed by the upstream process; permission changes after open on some filesystems.

Common situations: Piping output from a command that died mid-stream (broken pipe into `bd ... --description-file=-`); reading files on a disconnected NFS/network mount; hardware/disk errors on the volume holding the file.

Related errors


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