{"record":{"id":"d8757d24503e3b20","repo":"sipeed/picoclaw","slug":"conversation-not-found-for-s-after-ingest","errorCode":null,"errorMessage":"conversation not found for %s after ingest","messagePattern":"conversation not found for (.+?) after ingest","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/membench/ingest.go","lineNumber":74,"sourceCode":"\t\t\t\tRole:       \"user\",\n\t\t\t\tContent:    content,\n\t\t\t\tTokenCount: len(turn.Text) / 4,\n\t\t\t})\n\t\t}\n\n\t\t// Ingest all turns for this sample\n\t\t_, err := engine.Ingest(ctx, sessionKey, msgs)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"ingest sample %s: %w\", sample.SampleID, err)\n\t\t}\n\n\t\t// Get the conversation ID for scoped retrieval\n\t\tconv, err := store.GetConversationBySessionKey(ctx, sessionKey)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"get conversation for %s: %w\", sample.SampleID, err)\n\t\t}\n\t\tif conv == nil {\n\t\t\treturn nil, fmt.Errorf(\"conversation not found for %s after ingest\", sample.SampleID)\n\t\t}\n\t\tconvMap[sample.SampleID] = conv.ConversationID\n\t\tlog.Printf(\"Ingested sample %s: %d turns, convID=%d\", sample.SampleID, len(turns), conv.ConversationID)\n\t}\n\n\tlog.Printf(\"Seahorse ingestion complete: %d samples, %d conversations\", len(samples), len(convMap))\n\treturn &SeahorseIngestResult{\n\t\tEngine:  engine,\n\t\tConvMap: convMap,\n\t}, nil\n}\n","sourceCodeStart":56,"sourceCodeEnd":86,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/cmd/membench/ingest.go#L56-L86","documentation":"Invariant violation: engine.Ingest returned success, but the follow-up GetConversationBySessionKey returned (nil, nil) — no error, yet no conversation row for sessionKey 'locomo-<sampleID>'. The harness treats that as unrecoverable because scoped retrieval needs the conversation ID. In practice this points to an engine-side consistency gap (async commit, transaction not yet visible) rather than a caller mistake.","triggerScenarios":"Engine writes the conversation asynchronously/deferred so the row is not yet visible at read time; sessionKey normalization mismatch between Ingest and lookup; engine bug dropping empty-conversation creation when all messages filter out.","commonSituations":"Upgrading the seahorse engine to a version that changed visibility semantics; ingesting a sample whose turns list is empty after filtering; DB read happening on a different connection/snapshot than the write.","solutions":["Pin/upgrade to an engine version where Ingest is synchronous with respect to GetConversationBySessionKey","Log len(msgs) before Ingest — an empty turn list is the classic silent no-row case","Retry the lookup briefly (eventual visibility) before declaring failure","Report as an engine bug with the sample ID if it reproduces with non-empty input"],"exampleFix":"// before\nif conv == nil {\n    return nil, fmt.Errorf(\"conversation not found for %s after ingest\", sample.SampleID)\n}\n\n// after\nif conv == nil {\n    var err error\n    for i := 0; i < 3 && conv == nil; i++ {\n        time.Sleep(100 * time.Millisecond)\n        conv, err = store.GetConversationBySessionKey(ctx, sessionKey)\n        if err != nil { break }\n    }\n    if conv == nil {\n        return nil, fmt.Errorf(\"conversation not found for %s after ingest (turns=%d)\", sample.SampleID, len(msgs))\n    }\n}","handlingStrategy":"try-catch","validationCode":"if len(msgs) == 0 {\n    log.Printf(\"sample %s has no turns after filtering; skipping\", sample.SampleID)\n    continue\n}","typeGuard":null,"tryCatchPattern":"if conv == nil {\n    for i := 0; i < 3; i++ {\n        time.Sleep(100 * time.Millisecond)\n        conv, err = store.GetConversationBySessionKey(ctx, sessionKey)\n        if err != nil || conv != nil { break }\n    }\n    if conv == nil {\n        return nil, fmt.Errorf(\"engine bug: no conversation for %s after ingest (turns=%d)\", sample.SampleID, len(msgs))\n    }\n}","preventionTips":["Never call Ingest with an empty message slice — it can legitimately create no conversation","Pin a seahorse version where Ingest visibility is synchronous; re-test after upgrades","Treat this error as an engine invariant bug, not a data problem — file it with sampleID","Log turn counts per sample so the empty-input case is diagnosable"],"tags":["go","database","invariant","ingestion"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}