{"record":{"id":"5cf177637c833080","repo":"vxcontrol/pentagi","slug":"flow-not-found-5cf177","errorCode":null,"errorMessage":"flow not found","messagePattern":"flow not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"backend/pkg/controller/msglogs.go","lineNumber":64,"sourceCode":"func (mlc *msgLogController) ListFlowsMsgLog(ctx context.Context) ([]FlowMsgLogWorker, error) {\n\tmlc.mx.Lock()\n\tdefer mlc.mx.Unlock()\n\n\tflows := make([]FlowMsgLogWorker, 0, len(mlc.flows))\n\tfor _, flw := range mlc.flows {\n\t\tflows = append(flows, flw)\n\t}\n\n\treturn flows, nil\n}\n\nfunc (mlc *msgLogController) GetFlowMsgLog(ctx context.Context, flowID int64) (FlowMsgLogWorker, error) {\n\tmlc.mx.Lock()\n\tdefer mlc.mx.Unlock()\n\n\tflw, ok := mlc.flows[flowID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"flow not found\")\n\t}\n\n\treturn flw, nil\n}\n","sourceCodeStart":46,"sourceCodeEnd":69,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/msglogs.go#L46-L69","documentation":"GetFlowMsgLog returns the in-memory message-log worker registered for a flow. The controller keeps workers in a map keyed by flow ID; if the ID is absent (map miss), it returns a plain error \"flow not found\". This is a lookup miss on runtime state, not a database query — only flows with an active, loaded msg-log worker can be retrieved.","triggerScenarios":"Calling MsgLogController.GetFlowMsgLog(ctx, flowID) with a flowID that was never registered (no flow worker started), a flow that already finished and was removed from the map, or a backend restart (workers are in-memory only and not rehydrated for this controller).","commonSituations":"Client requesting message logs for a closed/finished flow; stale flow ID cached in the UI after a backend restart; race where the flow finished between listing and fetching; using a flow ID from a different environment/database.","solutions":["Check that the flow ID is correct and the flow is currently active.","Distinguish this error from ErrFlowNotFound handling — it is a plain fmt.Errorf, so compare by string or add a sentinel if you need programmatic checks.","Fetch message logs from the database for finished flows instead of the in-memory worker.","After a backend restart, reload the flow list before querying per-flow workers."],"exampleFix":"// before: treating any error as transient\nflw, err := msgLogs.GetFlowMsgLog(ctx, flowID)\n\n// after: handle the not-found case explicitly\nflw, err := msgLogs.GetFlowMsgLog(ctx, flowID)\nif err != nil {\n    if strings.Contains(err.Error(), \"flow not found\") {\n        // fall back to persisted msg logs or return 404 to the client\n        return nil, ErrFlowNotFound\n    }\n    return nil, err\n}","handlingStrategy":"type-guard","validationCode":"// only query workers for flows you know are currently loaded\nactive, err := flows.ListFlows(ctx)\nif err != nil {\n    return err\n}\n// ensure flowID is among active flows before calling GetFlowMsgLog","typeGuard":"func isFlowNotFoundError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"flow not found\")\n}","tryCatchPattern":"flw, err := msgLogs.GetFlowMsgLog(ctx, flowID)\nif err != nil {\n    if isFlowNotFoundError(err) {\n        return nil, ErrFlowNotFound // map to 404 upstream\n    }\n    return nil, err\n}","preventionTips":["Don't cache flow IDs client-side across backend restarts — workers are in-memory only.","Treat finished flows as not-found for per-flow worker lookups.","Prefer database-backed msg-log queries for historical flows.","Handle the miss as a normal 404 condition, not an infrastructure failure."],"tags":["go","not-found","in-memory-state","flow-lifecycle"],"backgroundTag":"flow-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}