charmbracelet/crush · error

error creating file history: %w

Error message

error creating file history: %w

What it means

After successfully writing the new file, createNewFile records it in the session file history via edit.files.Create (SQLite-backed). If that DB insert fails, this error is returned even though the file was already written to disk. The operation partially succeeded: content is on disk, but session history/tracking is missing.

Source

Thrown at internal/agent/tools/edit.go:172

		resp = fantasy.WithResponseMetadata(resp, EditResponseMetadata{
			OldContent: "",
			NewContent: content,
			Additions:  additions,
			Removals:   removals,
		})
		return resp, nil
	}

	err = os.WriteFile(filePath, []byte(content), 0o644)
	if err != nil {
		return fantasy.ToolResponse{}, fmt.Errorf("failed to write file: %w", err)
	}

	// File can't be in the history so we create a new file history
	_, err = edit.files.Create(edit.ctx, sessionID, filePath, "")
	if err != nil {
		// Log error but don't fail the operation
		return fantasy.ToolResponse{}, fmt.Errorf("error creating file history: %w", err)
	}

	// Add the new content to the file history
	_, err = edit.files.CreateVersion(edit.ctx, sessionID, filePath, content)
	if err != nil {
		// Log error but don't fail the operation
		slog.Error("Error creating file history version", "error", err)
	}

	edit.filetracker.RecordRead(edit.ctx, sessionID, filePath)

	return fantasy.WithResponseMetadata(
		fantasy.NewTextResponse("File created: "+filePath),
		EditResponseMetadata{
			OldContent: "",
			NewContent: content,
			Additions:  additions,
			Removals:   removals,

View on GitHub (pinned to 7944b8e522)

Solutions

  1. Inspect the wrapped %w cause for a SQLite error (database is locked, no such table, disk I/O error).
  2. Ensure only one crush process uses the same DB at a time; close other sessions.
  3. Verify the session ID is valid and the session exists (recreate the session if needed).
  4. Check that the data directory holding the SQLite file is writable and has free space; re-run migrations if tables are missing.
Defensive patterns

Strategy: retry

Validate before calling

// before edits, confirm the DB is reachable and the session exists
if _, err := os.Stat(dbPath); err != nil {
	return fmt.Errorf("DB unavailable: %w", err)
}
if err := db.PingContext(ctx); err != nil {
	return fmt.Errorf("DB ping failed: %w", err)
}

Try / catch

var serr *sqlite.Error
if errors.As(err, &serr) && strings.Contains(err.Error(), "database is locked") {
	time.Sleep(250 * time.Millisecond)
	// retry once; else fail with the wrapped cause surfaced
}

Prevention

When it happens

Trigger: os.WriteFile succeeded but files.Create(ctx, sessionID, filePath, "") fails — e.g. the database is locked, corrupt, read-only, or the sessionID is stale/missing from the session table.

Common situations: SQLite DB locked by another crush process, migration mismatch, the session row was deleted concurrently, or the data directory is on a read-only/full volume.

Related errors


AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29). Data as JSON: /api/errors/3835542b3d9da776. Report an issue: GitHub.