sipeed/picoclaw · error

get conversation for %s: %w

Error message

get conversation for %s: %w

What it means

Store().GetConversationBySessionKey returned a non-nil error right after a successful Ingest for the same sample. The lookup maps sessionKey "locomo-<sampleID>" to the internal conversation ID used for scoped retrieval; if the underlying query fails (DB error, context cancelled), the wrap 'get conversation for <id>' propagates and ingestion aborts.

Source

Thrown at cmd/membench/ingest.go:71

		for _, turn := range turns {
			content := turn.Speaker + ": " + turn.Text
			msgs = append(msgs, seahorse.Message{
				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

  1. Check whether ctx is already cancelled and widen the deadline if so
  2. Verify nothing else closes the engine/DB during ingestion (single owner)
  3. Retry the single lookup once after a short sleep — it usually succeeds since Ingest reported OK
  4. Move the DB to local disk to remove network-fs read flakiness

Example fix

// before
conv, err := store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil {
    return nil, fmt.Errorf("get conversation for %s: %w", sample.SampleID, err)
}

// after
conv, err := store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil && ctx.Err() == nil {
    time.Sleep(200 * time.Millisecond)
    conv, err = store.GetConversationBySessionKey(ctx, sessionKey)
}
if err != nil {
    return nil, fmt.Errorf("get conversation for %s: %w", sample.SampleID, err)
}
Defensive patterns

Strategy: try-catch

Try / catch

conv, err := store.GetConversationBySessionKey(ctx, sessionKey)
if err != nil {
    if ctx.Err() != nil {
        return nil, ctx.Err()
    }
    time.Sleep(200 * time.Millisecond) // fresh-write visibility
    conv, err = store.GetConversationBySessionKey(ctx, sessionKey)
    if err != nil {
        return nil, fmt.Errorf("get conversation for %s: %w", sample.SampleID, err)
    }
}

Prevention

When it happens

Trigger: Sqlite read error immediately after the write (I/O error, DB closed concurrently); ctx cancelled between Ingest and the lookup; store handle invalidated by engine shutdown in another goroutine.

Common situations: Timeout budget that expires mid-sample; tests closing the engine while ingestion runs; flaky network-backed sqlite (NFS) where a fresh read races the write.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/e4b1f591579b4800. Report an issue: GitHub.