vxcontrol/pentagi · error
failed to delete assistant %d: %w
Error message
failed to delete assistant %d: %w
What it means
DeleteAssistant wraps the error from fw.flowCtx.DB.DeleteAssistant(ctx, assistantID) — the database delete of the assistant row. The in-memory worker was already finished and removed; only the persistence layer failed, so the AssistantDeleted event is not published and the assistant record remains in the database.
Source
Thrown at backend/pkg/controller/flow.go:615
return nil, fmt.Errorf("assistant %d not found", assistantID)
}
func (fw *flowWorker) DeleteAssistant(ctx context.Context, assistantID int64) error {
fw.awsMX.Lock()
defer fw.awsMX.Unlock()
aw, ok := fw.aws[assistantID]
if ok {
if err := aw.Finish(ctx); err != nil {
return fmt.Errorf("failed to finish assistant %d: %w", assistantID, err)
}
delete(fw.aws, assistantID)
}
if assistant, err := fw.flowCtx.DB.DeleteAssistant(ctx, assistantID); err != nil {
return fmt.Errorf("failed to delete assistant %d: %w", assistantID, err)
} else {
fw.flowCtx.Publisher.AssistantDeleted(ctx, assistant)
}
return nil
}
func (fw *flowWorker) ListAssistants(ctx context.Context) []AssistantWorker {
fw.awsMX.Lock()
defer fw.awsMX.Unlock()
assistants := make([]AssistantWorker, 0, len(fw.aws))
for _, aw := range fw.aws {
assistants = append(assistants, aw)
}
slices.SortFunc(assistants, func(a, b AssistantWorker) int {
return int(a.GetAssistantID() - b.GetAssistantID())View on GitHub (pinned to ea665308ba)
Solutions
- Inspect the wrapped DB error: if it's a connection/pool issue, verify PostgreSQL is reachable and pool settings are adequate.
- Handle the already-deleted race: check for sql.ErrNoRows / duplicate-key semantics and treat idempotent deletes as success.
- Retry the delete with a fresh context after the DB recovers; the assistant is already gone from memory.
- Ensure the DB migrations are current (goose) so the assistants table schema matches the queries.
Example fix
// before ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() err := fw.DeleteAssistant(ctx, id) // ctx expires mid-DELETE // after ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() err := fw.DeleteAssistant(ctx, id)
Defensive patterns
Strategy: retry
Validate before calling
if err := db.PingContext(ctx); err != nil {
return fmt.Errorf("database unreachable before delete: %w", err)
} Type guard
func isNoRows(err error) bool {
return errors.Is(err, sql.ErrNoRows)
} Try / catch
if err := fw.DeleteAssistant(ctx, id); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil // already deleted; idempotent success
}
if isTransientDBErr(err) {
return retryWithBackoff(3, func() error { return fw.DeleteAssistant(ctx, id) })
}
return err
} Prevention
- Treat delete as idempotent: handle already-deleted rows as success.
- Use contexts with adequate deadlines for DB operations.
- Monitor PostgreSQL pool saturation before bulk assistant operations.
- Avoid concurrent DeleteAssistant calls for the same ID.
When it happens
Trigger: Calling DeleteAssistant when the SQLC/database DeleteAssistant query fails: DB connection dropped, row already deleted (constraint or NoRows behavior), transaction deadlock, or context cancelled during the query.
Common situations: PostgreSQL restarted or connection pool exhausted under load; two concurrent DeleteAssistant calls racing on the same assistantID; migration drift leaving the assistants table in an unexpected state; long-running request whose ctx times out mid-query.
Related errors
- failed to create flow in DB: %w
- failed to rename flow %d: %w
- failed to update flow provider in DB: %w
- failed to create vector store log: %w
- failed to get vector store log: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/096957cfdcaea627.
Report an issue: GitHub.