JuliusBrussee/caveman · error · ErrMemoryTooLarge

: memory is bytes, over the -byte cap

Error message

%w: memory is %d bytes, over the %d-byte cap

What it means

validateMemorySize rejects memory text larger than MaxMemoryBytes, returning the sentinel ErrMemoryTooLarge wrapped with the actual and maximum byte counts. Remember and Supersede both call it so oversized content never reaches the database.

Solutions

  1. Check len(text) against MaxMemoryBytes in the caller before invoking Remember/Supersede and reject early with a clear message.
  2. Split large content into multiple smaller memories and supersede/link them.
  3. Trim or summarize the text so it fits under the cap.
  4. Check byte length (not rune count) for multibyte input.

Example fix

// before
_, err := store.Remember(bigText) // ErrMemoryTooLarge at runtime
// after
if len(bigText) > mem.MaxMemoryBytes {
	return fmt.Errorf("input is %d bytes; split under %d", len(bigText), mem.MaxMemoryBytes)
}
_, err := store.Remember(bigText)
Defensive patterns

Strategy: validation

Validate before calling

if len(text) > mem.MaxMemoryBytes {
	return fmt.Errorf("memory text is %d bytes; max is %d", len(text), mem.MaxMemoryBytes)
}

Try / catch

if err := mem.ErrMemoryTooLarge; errors.Is(err, storeErr) { ... }

Prevention

When it happens

Trigger: Calling Store.Remember(text) or Store.Supersede(oldID, text) where len(text) > MaxMemoryBytes — e.g. pasting a large file's contents as a single memory.

Common situations: Users piping whole log files or documents into the memory CLI; forgetting that the cap counts bytes (UTF-8 multibyte text), not characters; building batches that concatenate many notes into one memory.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/bbb6b791878f9ef1. Report an issue: GitHub.

Appendix: source

Thrown at mem/store.go:270

	}
	if n, _ := res.RowsAffected(); n != 1 {
		return Memory{}, fmt.Errorf("memory %s changed during supersede", oldID)
	}
	if err := tx.Commit(); err != nil {
		return Memory{}, fmt.Errorf("supersede commit: %w", err)
	}
	return Memory{
		ID:         newID,
		Text:       newText,
		CreatedAt:  now,
		ValidFrom:  now,
		Supersedes: oldID,
	}, nil
}

func validateMemorySize(text string) error {
	if len(text) > MaxMemoryBytes {
		return fmt.Errorf("%w: memory is %d bytes, over the %d-byte cap", ErrMemoryTooLarge, len(text), MaxMemoryBytes)
	}
	return nil
}

// History returns the complete oldest-to-newest supersession chain containing
// id. Broken/cyclic lineage is rejected rather than returning partial history.
func (s *Store) History(id string) ([]Memory, error) {
	if strings.TrimSpace(id) == "" {
		return nil, fmt.Errorf("history requires memory id")
	}
	current, err := s.memoryByID(id)
	if err != nil {
		return nil, err
	}
	seen := map[string]bool{current.ID: true}
	var before []Memory
	cursor := current
	for cursor.Supersedes != "" {

View on GitHub (pinned to 3ee70a1026)