{"record":{"id":"3745f5b7b1de2c3f","repo":"Tencent/WeKnora","slug":"check-forgotten-memory-w","errorCode":null,"errorMessage":"check forgotten memory: %w","messagePattern":"check forgotten memory: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/memory/service.go","lineNumber":328,"sourceCode":"\t\tif types.IsMostlyRedacted(redacted) {\n\t\t\tlogger.Infof(ctx, \"memory: dropped a statement that was mostly sensitive material\")\n\t\t\treturn nil, ErrSensitiveContent\n\t\t}\n\t\tlogger.Infof(ctx, \"memory: redacted sensitive material before storing\")\n\t\tcontent = types.SanitizeMemoryContent(redacted)\n\t}\n\tif !types.IsValidMemoryKind(item.Kind) {\n\t\titem.Kind = types.MemoryKindFact\n\t}\n\n\t// Something the user deliberately forgot must not come back the next time\n\t// distillation reads the message it came from. Two checks, because the\n\t// re-derived statement is usually worded slightly differently and so does\n\t// not hash the same: the exact fingerprint, and whether the message it came\n\t// from already produced a memory the user rejected.\n\tforgotten, err := s.repo.HasTombstone(ctx, scope, types.MemoryFingerprint(content))\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"check forgotten memory: %w\", err)\n\t}\n\tif !forgotten && item.SourceMessageID != \"\" && item.Origin == types.MemoryOriginExtracted {\n\t\t// Only the background path is gated this way. An explicit \"remember\n\t\t// this\" is the user asking again, and must always win.\n\t\tforgotten, err = s.repo.HasTombstoneForMessage(\n\t\t\tctx, scope, item.SourceMessageID, rejectedMessageWindow,\n\t\t)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"check forgotten source: %w\", err)\n\t\t}\n\t}\n\tif forgotten {\n\t\tlogger.Infof(ctx, \"memory: skipped a statement the user previously deleted\")\n\t\treturn nil, ErrPreviouslyForgotten\n\t}\n\tif _, err := s.repo.EnsureSubject(ctx, scope); err != nil {\n\t\treturn nil, fmt.Errorf(\"ensure memory subject: %w\", err)\n\t}","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/memory/service.go#L310-L346","documentation":"During memory write, HasTombstone checks whether an identical statement fingerprint was previously deleted by the user; a repository failure on that check aborts the write with this wrapped error. It exists so a tombstone lookup failure can never cause a deleted memory to be silently re-added.","triggerScenarios":"Any write-path caller (mergeRedundant, applyDecisions, Remember, PromoteTopic, CreateItem, observeTopics) triggers write(), and repo.HasTombstone fails — typically a database error, timeout, or connection issue on the tombstone table.","commonSituations":"Database temporarily unavailable; migration missing the tombstones table/index; context canceled mid-query during shutdown; connection pool exhausted.","solutions":["Check database connectivity and recent DB error logs at the time of the failure","Verify the tombstone schema/table exists (HasTombstone query succeeds manually)","Retry the operation after the transient DB issue clears — the watermark design keeps data safe","Increase DB connection pool limits if under heavy write load"],"exampleFix":"// before\nitem, err := memSvc.Remember(ctx, scope, item)\n// after\nitem, err := memSvc.Remember(ctx, scope, item)\nif err != nil && strings.Contains(err.Error(), \"check forgotten memory\") {\n\ttime.Sleep(retryBackoff)\n\titem, err = memSvc.Remember(ctx, scope, item) // safe to retry; nothing was written\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"func isTombstoneCheckErr(err error) bool {\n\treturn err != nil && strings.Contains(err.Error(), \"check forgotten memory\")\n}","tryCatchPattern":"item, err := memSvc.Remember(ctx, scope, item)\nif err != nil {\n\tif isTombstoneCheckErr(err) {\n\t\t// safe to retry: write aborted before any insert\n\t\treturn retryWithBackoff(ctx, 3, call)\n\t}\n\treturn err\n}","preventionTips":["Keep the tombstone table and its fingerprint index migrated in all environments","Monitor DB health; these wrapped errors usually indicate an outage","Use bounded context timeouts so canceled contexts don't surface as this error","Treat write-path memory errors as safe-to-retry (watermark design prevents loss)"],"tags":["memory","database","tombstone"],"backgroundTag":"database-query-failed","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}