vxcontrol/pentagi · warning · ErrFlowNotFound
flow not found
Error message
flow not found
What it means
ErrFlowNotFound is the public sentinel error returned by GetFlow, StopFlow, FinishFlow, RenameFlow, DeleteFlow, and PatchAssistant when no flow with the given ID exists for the caller. It is a fixed message ('flow not found'), intended to be matched with errors.Is rather than string comparison. Callers should treat it as a 404-class condition.
Source
Thrown at backend/pkg/controller/flows.go:23
"errors"
"fmt"
"sort"
"sync"
"time"
"pentagi/pkg/config"
"pentagi/pkg/database"
"pentagi/pkg/docker"
"pentagi/pkg/graph/subscriptions"
"pentagi/pkg/providers"
"pentagi/pkg/providers/provider"
"pentagi/pkg/tools"
"github.com/sirupsen/logrus"
)
var (
ErrFlowNotFound = fmt.Errorf("flow not found")
ErrFlowAlreadyStopped = fmt.Errorf("flow already stopped")
)
type FlowController interface {
CreateFlow(
ctx context.Context,
userID int64,
input string,
prvname provider.ProviderName,
prvtype provider.ProviderType,
functions *tools.Functions,
resources []database.UserResource,
) (FlowWorker, error)
CreateAssistant(
ctx context.Context,
userID int64,
flowID int64,
input string,View on GitHub (pinned to ea665308ba)
Solutions
- Verify the flowID via GetFlow or the flows list before mutating operations.
- After a server restart, wait for LoadFlows to finish or re-fetch the flow list.
- Handle it as 404 in the API layer and refresh client state.
- Check errors.Is(err, controller.ErrFlowNotFound) instead of string matching.
Example fix
// before
flow, err := fc.GetFlow(ctx, flowID)
if err != nil {
return fmt.Errorf("get flow: %w", err)
}
// after
flow, err := fc.GetFlow(ctx, flowID)
if err != nil {
if errors.Is(err, controller.ErrFlowNotFound) {
return http.StatusNotFound // or refresh flow list
}
return fmt.Errorf("get flow: %w", err)
} Defensive patterns
Strategy: type-guard
Validate before calling
var exists bool
err := db.QueryRow("SELECT EXISTS(SELECT 1 FROM flows WHERE id=$1)", flowID).Scan(&exists)
// only call GetFlow/StopFlow/etc. when exists == true Type guard
func IsFlowNotFound(err error) bool {
return errors.Is(err, controller.ErrFlowNotFound)
} Try / catch
flow, err := fc.GetFlow(ctx, flowID)
if err != nil {
if IsFlowNotFound(err) {
return ErrHTTP404 // refresh client flow list
}
return fmt.Errorf("get flow: %w", err)
} Prevention
- Always match with errors.Is, never string comparison.
- Re-fetch the flow list after server restarts (LoadFlows repopulates workers).
- Treat as 404 in API handlers and update stale client IDs.
- Guard against delete/use races by checking existence before mutations.
When it happens
Trigger: Any FlowController operation (GetFlow/StopFlow/FinishFlow/RenameFlow/DeleteFlow/PatchAssistant) called with a flowID that is not registered in the controller's flow map — e.g., after process restart before LoadFlows, or for an ID that never existed or was deleted.
Common situations: Client caches a flowID after server restart (workers not yet loaded); UI uses a stale ID after another user deleted the flow; race between DeleteFlow and a subsequent call; querying before startup LoadFlows completes.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/c0bb465a23740889.
Report an issue: GitHub.