vxcontrol/pentagi · error
failed to get containers: %w
Error message
failed to get containers: %w
What it means
GetContainers lists all containers for the worker's flow via db.GetFlowContainers and wraps any database failure. It is also called internally by PutMsg when refreshing the container cache, in which case this error propagates out of PutMsg unchanged (it is returned raw, not re-wrapped).
Source
Thrown at backend/pkg/controller/termlog.go:96
tlw.pub.TerminalLogAdded(ctx, termLog)
return termLog.ID, nil
}
func (tlw *flowTermLogWorker) GetMsg(ctx context.Context, msgID int64) (database.Termlog, error) {
msg, err := tlw.db.GetTermLog(ctx, msgID)
if err != nil {
return database.Termlog{}, fmt.Errorf("failed to get termlog: %w", err)
}
return msg, nil
}
func (tlw *flowTermLogWorker) GetContainers(ctx context.Context) ([]database.Container, error) {
containers, err := tlw.db.GetFlowContainers(ctx, tlw.flowID)
if err != nil {
return nil, fmt.Errorf("failed to get containers: %w", err)
}
return containers, nil
}
View on GitHub (pinned to ea665308ba)
Solutions
- Check the wrapped error for connection vs timeout vs constraint causes
- Verify DB health (docker compose ps, pg_isready) and connection pool saturation
- Give container refreshes a background context with a sane timeout instead of a request ctx
- Add retry with backoff for transient errors before failing the terminal write
- Check indexes/latency on containers.flow_id if the query is slow
Example fix
// before
containers, err := termWorker.GetContainers(ctx) // request ctx may be canceled
if err != nil { return err }
// after
containers, err := termWorker.GetContainers(context.WithoutCancel(ctx))
if err != nil {
if isTransient(err) { time.Sleep(backoff); containers, err = termWorker.GetContainers(ctx) }
if err != nil { return err }
} Defensive patterns
Strategy: retry
Validate before calling
func dbReachable(ctx context.Context, q database.Querier) error {
c, err := q.Conn(ctx)
if err != nil { return err }
return c.Ping(ctx)
} Type guard
func isTransientDBErr(err error) bool {
return errors.Is(err, driver.ErrBadConn) ||
errors.Is(err, context.DeadlineExceeded) ||
errors.Is(err, pgconn.ErrTimeout)
} Try / catch
containers, err := w.GetContainers(ctx)
if isTransientDBErr(err) {
time.Sleep(250 * time.Millisecond)
containers, err = w.GetContainers(ctx)
}
if err != nil {
return nil, fmt.Errorf("list containers: %w", err)
} Prevention
- Verify Postgres health (pg_isready, compose ps) when this fires repeatedly
- Use a background context with timeout for internal container-cache refreshes
- Watch connection-pool saturation under heavy agent/terminal load
- Check indexes on containers.flow_id if listing is slow
- Retry with backoff; never swallow the wrapped cause when surfacing to callers
When it happens
Trigger: DB connection loss, canceled context, or query timeout while listing flow containers; also fires indirectly whenever PutMsg sees an unknown containerID and the refresh query fails.
Common situations: Postgres restarts under heavy terminal/agent load; slow queries on the containers table blocking the flow worker's mutex (PutMsg holds tlw.mx during refresh); context deadlines from request scoping.
Understand the failure class
Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.
Related errors
- failed to create tool call log: %w
- failed to update tool call log result: %w
- failed to update tool call log failed result: %w
- failed to create termlog: %w
- knowledge: list user docs: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/26e065c117a64234.
Report an issue: GitHub.