sipeed/picoclaw · error
conversation not found for %s after ingest
Error message
conversation not found for %s after ingest
What it means
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.
Source
Thrown at cmd/membench/ingest.go:74
Role: "user",
Content: content,
TokenCount: len(turn.Text) / 4,
})
}
// Ingest all turns for this sample
_, err := engine.Ingest(ctx, sessionKey, msgs)
if err != nil {
return nil, fmt.Errorf("ingest sample %s: %w", sample.SampleID, err)
}
// Get the conversation ID for scoped retrieval
conv, err := store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil {
return nil, fmt.Errorf("get conversation for %s: %w", sample.SampleID, err)
}
if conv == nil {
return nil, fmt.Errorf("conversation not found for %s after ingest", sample.SampleID)
}
convMap[sample.SampleID] = conv.ConversationID
log.Printf("Ingested sample %s: %d turns, convID=%d", sample.SampleID, len(turns), conv.ConversationID)
}
log.Printf("Seahorse ingestion complete: %d samples, %d conversations", len(samples), len(convMap))
return &SeahorseIngestResult{
Engine: engine,
ConvMap: convMap,
}, nil
}
View on GitHub (pinned to 49183d7e8d)
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
Example fix
// before
if conv == nil {
return nil, fmt.Errorf("conversation not found for %s after ingest", sample.SampleID)
}
// after
if conv == nil {
var err error
for i := 0; i < 3 && conv == nil; i++ {
time.Sleep(100 * time.Millisecond)
conv, err = store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil { break }
}
if conv == nil {
return nil, fmt.Errorf("conversation not found for %s after ingest (turns=%d)", sample.SampleID, len(msgs))
}
} Defensive patterns
Strategy: try-catch
Validate before calling
if len(msgs) == 0 {
log.Printf("sample %s has no turns after filtering; skipping", sample.SampleID)
continue
} Try / catch
if conv == nil {
for i := 0; i < 3; i++ {
time.Sleep(100 * time.Millisecond)
conv, err = store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil || conv != nil { break }
}
if conv == nil {
return nil, fmt.Errorf("engine bug: no conversation for %s after ingest (turns=%d)", sample.SampleID, len(msgs))
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- ingest sample %s: %w
- get conversation for %s: %w
- create seahorse engine: %w
- failed to decode serialized config: %w
- feishu channel is not supported on 32-bit architectures (arm
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/d8757d24503e3b20.
Report an issue: GitHub.