{"record":{"id":"bbb6b791878f9ef1","repo":"JuliusBrussee/caveman","slug":"w-memory-is-d-bytes-over-the-d-byte-cap","errorCode":null,"errorMessage":"%w: memory is %d bytes, over the %d-byte cap","messagePattern":"%w: memory is (.+?) bytes, over the (.+?)-byte cap","errorType":"validation","errorClass":"ErrMemoryTooLarge","httpStatus":null,"severity":"error","filePath":"mem/store.go","lineNumber":270,"sourceCode":"\t}\n\tif n, _ := res.RowsAffected(); n != 1 {\n\t\treturn Memory{}, fmt.Errorf(\"memory %s changed during supersede\", oldID)\n\t}\n\tif err := tx.Commit(); err != nil {\n\t\treturn Memory{}, fmt.Errorf(\"supersede commit: %w\", err)\n\t}\n\treturn Memory{\n\t\tID:         newID,\n\t\tText:       newText,\n\t\tCreatedAt:  now,\n\t\tValidFrom:  now,\n\t\tSupersedes: oldID,\n\t}, nil\n}\n\nfunc validateMemorySize(text string) error {\n\tif len(text) > MaxMemoryBytes {\n\t\treturn fmt.Errorf(\"%w: memory is %d bytes, over the %d-byte cap\", ErrMemoryTooLarge, len(text), MaxMemoryBytes)\n\t}\n\treturn nil\n}\n\n// History returns the complete oldest-to-newest supersession chain containing\n// id. Broken/cyclic lineage is rejected rather than returning partial history.\nfunc (s *Store) History(id string) ([]Memory, error) {\n\tif strings.TrimSpace(id) == \"\" {\n\t\treturn nil, fmt.Errorf(\"history requires memory id\")\n\t}\n\tcurrent, err := s.memoryByID(id)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tseen := map[string]bool{current.ID: true}\n\tvar before []Memory\n\tcursor := current\n\tfor cursor.Supersedes != \"\" {","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/mem/store.go#L252-L288","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check len(text) against MaxMemoryBytes in the caller before invoking Remember/Supersede and reject early with a clear message.","Split large content into multiple smaller memories and supersede/link them.","Trim or summarize the text so it fits under the cap.","Check byte length (not rune count) for multibyte input."],"exampleFix":"// before\n_, err := store.Remember(bigText) // ErrMemoryTooLarge at runtime\n// after\nif len(bigText) > mem.MaxMemoryBytes {\n\treturn fmt.Errorf(\"input is %d bytes; split under %d\", len(bigText), mem.MaxMemoryBytes)\n}\n_, err := store.Remember(bigText)","handlingStrategy":"validation","validationCode":"if len(text) > mem.MaxMemoryBytes {\n\treturn fmt.Errorf(\"memory text is %d bytes; max is %d\", len(text), mem.MaxMemoryBytes)\n}","typeGuard":null,"tryCatchPattern":"if err := mem.ErrMemoryTooLarge; errors.Is(err, storeErr) { ... }","preventionTips":["Check byte length (len), not character count, before Remember/Supersede","Split or summarize large documents into multiple memories","Validate user/piped input size at the CLI boundary","Reference the exported MaxMemoryBytes constant instead of hardcoding a limit"],"tags":["validation","size-limit","input"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}