cayleygraph/cayley · error

could not write history to %q: %v

Error message

could not write history to %q: %v

What it means

This error is returned by the persist function in internal/repl/repl.go when the liner terminal fails to write the accumulated readline history to the history file on disk. The history file was opened successfully (OS-level open succeeded), but term.WriteHistory(f) failed while serializing or writing the history entries. It wraps the underlying liner error with the file path for context.

Source

Thrown at internal/repl/repl.go:280

	f, err := os.Open(path)
	if err != nil {
		return term, err
	}
	defer f.Close()
	_, err = term.ReadHistory(f)
	return term, err
}

func persist(term *liner.State, path string) error {
	f, err := os.OpenFile(path, os.O_RDWR|os.O_APPEND|os.O_CREATE, 0666)
	if err != nil {
		return fmt.Errorf("could not open %q to append history: %v", path, err)
	}
	defer f.Close()
	_, err = term.WriteHistory(f)
	if err != nil {
		return fmt.Errorf("could not write history to %q: %v", path, err)
	}
	return term.Close()
}

View on GitHub (pinned to 81dcd7d73e)

Solutions

  1. Check the wrapped %v error for the underlying cause (ENOSPC, EIO, EBADF) and free disk space or fix the filesystem
  2. Verify the history file path is on a writable, available filesystem
  3. Check that no other process holds a conflicting lock on the history file
  4. Retry persisting, or fall back to skipping history persistence so the REPL still exits cleanly

Example fix

// before
_, err = term.WriteHistory(f)
if err != nil {
    return fmt.Errorf("could not write history to %q: %v", path, err)
}
// after
_, err = term.WriteHistory(f)
if err != nil {
    log.Printf("warning: history not saved to %q: %v", path, err)
    return nil // don't fail REPL shutdown over history persistence
}
Defensive patterns

Strategy: try-catch

Validate before calling

f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0666)
if err != nil { return err }
f.Close()
// disk space check (unix)
// syscall.Statfs(path, &st); if st.Bavail*uint64(st.Bsize) < minFree { ... }

Try / catch

if err := persist(term, historyPath); err != nil {
    if strings.Contains(err.Error(), "could not write history") {
        log.Printf("history not saved: %v", err) // degrade gracefully
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Calling persist(term, path) where os.OpenFile succeeded but liner's WriteHistory fails — e.g. the file descriptor becomes invalid mid-write, the disk fills up, or the liner state is corrupted/closed before the write. It is invoked during REPL shutdown/cleanup paths from Repl and an anonymous cleanup goroutine.

Common situations: Disk-full or quota-exceeded while exiting a REPL session; history file on a network mount that dropped; another process truncating or locking the history file concurrently; file system became read-only after open.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


AI-assisted analysis of cayleygraph/cayley@81dcd7d73e (2026-09-06). Data as JSON: /api/errors/d92924be29b6a141. Report an issue: GitHub.