vxcontrol/pentagi · error
failed to get termlog: %w
Error message
failed to get termlog: %w
What it means
GetMsg fetches a single terminal log row by message ID via db.GetTermLog (no flow scoping in the query itself). Any failure — most often sql.ErrNoRows for a deleted/never-existing message ID — is wrapped with this message. Transient DB errors are wrapped identically.
Source
Thrown at backend/pkg/controller/termlog.go:87
Text: database.SanitizeUTF8(msg),
ContainerID: containerID,
FlowID: tlw.flowID,
TaskID: database.Int64ToNullInt64(taskID),
SubtaskID: database.Int64ToNullInt64(subtaskID),
})
if err != nil {
return 0, fmt.Errorf("failed to create termlog: %w", err)
}
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 errors.Is(err, sql.ErrNoRows) and map to 404
- Confirm the message row still exists (retention may have purged it)
- Use the correct flow's FlowTermLogWorker for authorization before fetching
- Validate msgID > 0 and comes from a trusted source
- Retry only transient connection errors
Example fix
// before
msg, err := worker.GetMsg(ctx, msgID)
if err != nil { return err } // 500 for missing rows
// after
msg, err := worker.GetMsg(ctx, msgID)
if errors.Is(err, sql.ErrNoRows) { return nil, ErrTermlogNotFound }
if err != nil { return err } Defensive patterns
Strategy: type-guard
Validate before calling
func validMsgID(id int64) bool { return id > 0 } Type guard
func termlogNotFound(err error) bool { return errors.Is(err, sql.ErrNoRows) } Try / catch
msg, err := w.GetMsg(ctx, msgID)
if termlogNotFound(err) {
return nil, httpErr(http.StatusNotFound, "termlog %d not found", msgID)
}
if err != nil {
return nil, fmt.Errorf("get termlog: %w", err)
} Prevention
- Map sql.ErrNoRows to 404 in handlers instead of a 500
- Account for retention policies deleting old termlog rows referenced by clients
- Validate message IDs before querying and scope authorization via the flow worker
- Treat subscription replays of purged rows as normal and skip them
- Retry only transient connection errors, never a no-rows result
When it happens
Trigger: Requesting a msgID that was deleted by retention/cleanup, an ID from another flow via a mismatched worker handle, or during a DB outage.
Common situations: Frontend subscription replays referencing pruned rows; clients caching message IDs across environment resets; pagination cursors pointing past deleted data.
Related errors
- failed to get screenshot: %w
- failed to get search log: %w
- failed to get tool call log: %w
- failed to get vector store log: %w
- knowledge: get document %s: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/cd461655eb773bbf.
Report an issue: GitHub.