{"record":{"id":"23e3761a77814e66","repo":"vxcontrol/pentagi","slug":"flow-not-found-23e376","errorCode":null,"errorMessage":"flow not found","messagePattern":"flow not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/aslogs.go","lineNumber":75,"sourceCode":"\t}\n\n\tflows := make([]FlowAssistantLogWorker, 0, len(aslc.flows[flowID]))\n\tfor _, flw := range aslc.flows[flowID] {\n\t\tflows = append(flows, flw)\n\t}\n\n\treturn flows, nil\n}\n\nfunc (aslc *assistantLogController) GetFlowAssistantLog(\n\tctx context.Context, flowID, assistantID int64,\n) (FlowAssistantLogWorker, error) {\n\taslc.mx.Lock()\n\tdefer aslc.mx.Unlock()\n\n\tflw, ok := aslc.flows[flowID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"flow not found\")\n\t}\n\n\taslw, ok := flw[assistantID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"assistant not found\")\n\t}\n\n\treturn aslw, nil\n}\n","sourceCodeStart":57,"sourceCodeEnd":85,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/aslogs.go#L57-L85","documentation":"GetFlowAssistantLog resolves a two-level in-memory map: flows[flowID][assistantID]. If the flow ID is absent from aslc.flows it returns 'flow not found' (a missing assistant ID yields the separate 'assistant not found' error). The worker registry only holds live assistant log workers.","triggerScenarios":"Requesting an assistant log for flow_id that has no registered FlowAssistantLogWorker — unknown/finished flow, service restart, or request arriving before worker registration completes.","commonSituations":"Subscribing to assistant logs after the flow ended, backend redeploy clearing the map, mistyped flow ID, or frontend reconnecting with cached IDs from a previous session.","solutions":["Confirm the flow is running and the ID is correct via the flows API","For terminated flows, read logs from persistent storage rather than the live worker","Retry after confirming the assistant worker was created (subscribe once the flow is active)","If IDs come from a saved session, refresh them after backend restarts"],"exampleFix":"// before\nawait assistantLog.getFlowAssistantLog(staleFlowId, assistantId); // flow not found\n// after\nconst flows = await api.listFlows();\nif (flows.some(f => f.id === flowId && f.status === 'running')) {\n  await assistantLog.getFlowAssistantLog(flowId, assistantId);\n}","handlingStrategy":"try-catch","validationCode":"const flow = await api.getFlow(flowId);\nif (!flow || flow.status !== 'running') throw new Error('flow not active');\nif (!flow.assistants?.includes(assistantId)) throw new Error('assistant not found');","typeGuard":"function isRegisteredAssistant(\n  flw: Record<string, FlowAssistantLogWorker> | undefined,\n  assistantId: string,\n): flw is Record<string, FlowAssistantLogWorker> {\n  return flw !== undefined && assistantId in flw;\n}","tryCatchPattern":"try {\n  const worker = await asstLogCtl.GetFlowAssistantLog(ctx, flowId, assistantId);\n  return worker.Stream();\n} catch (e) {\n  if (/flow not found/.test(String(e))) {\n    return loadPersistedAssistantLog(flowId, assistantId);\n  }\n  if (/assistant not found/.test(String(e))) {\n    return retryWithBackoff(() => asstLogCtl.GetFlowAssistantLog(ctx, flowId, assistantId));\n  }\n  throw e;\n}","preventionTips":["Gate log subscriptions on the flow's live status from GraphQL subscriptions","Handle the two-level lookup explicitly: check flow existence before assistant","Refresh cached flow/assistant IDs after service restarts","Prefer persisted log queries for any non-running flow"],"tags":["controller","logging","not-found","in-memory-state"],"backgroundTag":"resource-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}