{"record":{"id":"4eb523179141260b","repo":"vxcontrol/pentagi","slug":"flow-not-found-4eb523","errorCode":null,"errorMessage":"flow not found","messagePattern":"flow not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"backend/pkg/controller/screenshots.go","lineNumber":64,"sourceCode":"func (sc *screenshotController) ListFlowsScreenshot(ctx context.Context) ([]FlowScreenshotWorker, error) {\n\tsc.mx.Lock()\n\tdefer sc.mx.Unlock()\n\n\tflows := make([]FlowScreenshotWorker, 0, len(sc.flows))\n\tfor _, flw := range sc.flows {\n\t\tflows = append(flows, flw)\n\t}\n\n\treturn flows, nil\n}\n\nfunc (sc *screenshotController) GetFlowScreenshot(ctx context.Context, flowID int64) (FlowScreenshotWorker, error) {\n\tsc.mx.Lock()\n\tdefer sc.mx.Unlock()\n\n\tflw, ok := sc.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/screenshots.go#L46-L69","documentation":"GetFlowScreenshot returns the in-memory screenshot worker registered for a flow. If flowID is not present in the controller's map, it returns a plain \"flow not found\" error. Like the msg-log controller, this reflects runtime state only — workers exist only for currently loaded flows.","triggerScenarios":"Calling ScreenshotController.GetFlowScreenshot(ctx, flowID) for a flow that was never started, has finished (removed from the map on successful FinishFlow), or after a backend restart (in-memory workers are not restored here).","commonSituations":"Client fetching screenshots for a just-finished flow; stale flow ID cached in the frontend after restart; race between finishing a flow and a pending screenshot download; flow ID from a different environment.","solutions":["Confirm the flow is active and the ID is correct.","For finished flows, read screenshots from the database instead of the in-memory worker.","Handle this as a 404-class condition at the API boundary.","Refresh the flow list after backend restarts before issuing per-flow calls."],"exampleFix":"null","handlingStrategy":"type-guard","validationCode":"// confirm the flow is still active before requesting its screenshot worker\nworker, err := flows.GetFlow(ctx, flowID)\nif err != nil {\n    return err // flow already gone\n}","typeGuard":"func isFlowNotFoundError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"flow not found\")\n}","tryCatchPattern":"flw, err := screenshots.GetFlowScreenshot(ctx, flowID)\nif err != nil {\n    if isFlowNotFoundError(err) {\n        // fall back to DB-backed screenshot listing for finished flows\n        return listScreenshotsFromDB(ctx, flowID)\n    }\n    return nil, err\n}","preventionTips":["Avoid racing flow teardown: a flow removed by FinishFlow makes this lookup fail.","Keep a DB fallback for historical screenshots — the worker map is ephemeral.","Refresh flow state after backend restarts; workers are not rehydrated here.","Map this error to 404 at the API boundary."],"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"}