wavetermdev/waveterm · error

error writing to file %s: %w

Error message

error writing to file %s: %w

What it means

When the --output-file flag is set, wsh writes the scrollback text with os.WriteFile using 0644 permissions. Any filesystem failure (bad path, missing directory, permission denied, disk full) is wrapped with this message naming the file.

Source

Thrown at cmd/wsh/cmd/wshcmd-termscrollback.go:96

	result, err := wshclient.TermGetScrollbackLinesCommand(RpcClient, scrollbackData, &wshrpc.RpcOpts{
		Route:   wshutil.MakeFeBlockRouteId(fullORef.OID),
		Timeout: 5000,
	})
	if err != nil {
		return fmt.Errorf("error getting terminal scrollback: %w", err)
	}

	// Format the output
	output := strings.Join(result.Lines, "\n")
	if len(result.Lines) > 0 {
		output += "\n" // Add final newline
	}

	// Write to file or stdout
	if termScrollbackOutputFile != "" {
		err = os.WriteFile(termScrollbackOutputFile, []byte(output), 0644)
		if err != nil {
			return fmt.Errorf("error writing to file %s: %w", termScrollbackOutputFile, err)
		}
		fmt.Printf("terminal scrollback written to %s (%d lines)\n", termScrollbackOutputFile, len(result.Lines))
	} else {
		fmt.Print(output)
	}

	return nil
}

View on GitHub (pinned to a4447c1563)

Solutions

  1. Check the path exists and is writable: verify the parent directory exists (`mkdir -p`) and fix the filename.
  2. Avoid `~` — pass an absolute path since os.WriteFile does not expand tilde.
  3. Check filesystem permissions and free space (`ls -ld`, `df -h`).

Example fix

// before
err = os.WriteFile(termScrollbackOutputFile, []byte(output), 0644)
// after
expandedPath, err := wavebase.ExpandHomeDir(termScrollbackOutputFile)
if err != nil {
	return fmt.Errorf("invalid output path %s: %w", termScrollbackOutputFile, err)
}
if err := os.MkdirAll(filepath.Dir(expandedPath), 0755); err != nil {
	return fmt.Errorf("creating output dir: %w", err)
}
err = os.WriteFile(expandedPath, []byte(output), 0644)
Defensive patterns

Strategy: validation

Validate before calling

// validate the output path before writing
if termScrollbackOutputFile != "" {
	path, _ := filepath.Abs(os.ExpandEnv(termScrollbackOutputFile))
	if st, err := os.Stat(filepath.Dir(path)); err != nil || !st.IsDir() {
		fmt.Fprintf(os.Stderr, "output directory does not exist: %s\n", filepath.Dir(path))
		os.Exit(1)
	}
}

Try / catch

err = os.WriteFile(termScrollbackOutputFile, []byte(output), 0644)
if err != nil {
	if errors.Is(err, fs.ErrPermission) {
		// permission denied: fix ownership/mode or pick another path
	} else if errors.Is(err, fs.ErrNotExist) {
		// create parent dirs first
	}
	return fmt.Errorf("error writing to file %s: %w", termScrollbackOutputFile, err)
}

Prevention

When it happens

Trigger: os.WriteFile failing for termScrollbackOutputFile: parent directory doesn't exist, no write permission, read-only filesystem, or path is a directory.

Common situations: Typo in the output path; writing into a directory created by root; output on a full or read-only disk; using `~` unexpanded because the CLI doesn't expand it.

Understand the failure class

Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.

Related errors


AI-assisted analysis of wavetermdev/waveterm@a4447c1563 (2026-09-01). Data as JSON: /api/errors/14cc7694eb108bdb. Report an issue: GitHub.