{"record":{"id":"89cf7a67ae1ed578","repo":"vxcontrol/pentagi","slug":"flow-not-found-89cf7a","errorCode":null,"errorMessage":"flow not found","messagePattern":"flow not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/slogs.go","lineNumber":67,"sourceCode":"\n\tflows := make([]FlowSearchLogWorker, 0, len(slc.flows))\n\tfor _, flw := range slc.flows {\n\t\tflows = append(flows, flw)\n\t}\n\n\treturn flows, nil\n}\n\nfunc (slc *searchLogController) GetFlowSearchLog(\n\tctx context.Context,\n\tflowID int64,\n) (FlowSearchLogWorker, error) {\n\tslc.mx.Lock()\n\tdefer slc.mx.Unlock()\n\n\tflw, ok := slc.flows[flowID]\n\tif !ok {\n\t\treturn nil, fmt.Errorf(\"flow not found\")\n\t}\n\n\treturn flw, nil\n}\n","sourceCodeStart":49,"sourceCodeEnd":72,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/slogs.go#L49-L72","documentation":"GetFlowSearchLog looks up a cached FlowSearchLogWorker for a flowID in an in-memory map protected by a mutex. If no worker has been registered for that flowID, it returns a plain 'flow not found' error. It is a cache-lookup miss, not necessarily proof the flow is absent from the database.","triggerScenarios":"Calling GetFlowSearchLog(ctx, flowID) before the flow's worker was created/registered in slc.flows, after the worker was evicted/removed (e.g. flow finished and cleaned up), or with a mistyped flowID.","commonSituations":"Client polls search logs for a flow that already completed and whose worker was reaped; a server restart wiped the in-memory cache; concurrent request raced ahead of worker initialization.","solutions":["Ensure the flow is loaded/registered (creating its worker) before requesting its search log worker.","Check whether the flow already finished — if workers are cleaned up on completion, re-create or re-hydrate from the database.","Validate the flowID value on the caller side (correct type, non-zero, belongs to this instance).","After a server restart, treat the in-memory cache as empty and reload workers lazily from DB."],"exampleFix":"// before\nworker, err := slc.GetFlowSearchLog(ctx, flowID)\nif err != nil {\n    return err\n}\n// after\nworker, err := slc.GetFlowSearchLog(ctx, flowID)\nif err != nil {\n    if err.Error() == \"flow not found\" {\n        worker, err = slc.CreateFlowSearchLog(ctx, flowID) // lazy-init from DB\n        if err != nil {\n            return fmt.Errorf(\"flow %d not found: %w\", flowID, err)\n        }\n    } else {\n        return err\n    }\n}","handlingStrategy":"fallback","validationCode":"// guard: ensure the flow worker exists before use\nif flowID == 0 {\n    return fmt.Errorf(\"flowID required\")\n}\nslc.mx.Lock()\n_, ok := slc.flows[flowID]\nslc.mx.Unlock()\nif !ok { /* create/register worker first */ }","typeGuard":"func HasFlowWorker(slc *FlowSearchLogController, flowID int64) bool {\n    slc.mx.Lock()\n    defer slc.mx.Unlock()\n    _, ok := slc.flows[flowID]\n    return ok\n}","tryCatchPattern":"worker, err := slc.GetFlowSearchLog(ctx, flowID)\nif err != nil {\n    if err.Error() == \"flow not found\" {\n        // fallback: lazy-initialize or report 404\n        http.Error(w, \"flow not found\", http.StatusNotFound)\n        return\n    }\n    http.Error(w, \"internal error\", http.StatusInternalServerError)\n}","preventionTips":["Register the flow worker before exposing any log endpoints for that flow.","Do not serve requests for flows whose workers were cleaned up after completion.","After process restart, re-hydrate the worker map from the database before accepting traffic.","Prefer a sentinel exported error (ErrFlowNotFound) over a string literal for matching."],"tags":["cache-miss","not-found","concurrency"],"backgroundTag":"entity-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}