{"record":{"id":"2e704228459cecc4","repo":"vxcontrol/pentagi","slug":"failed-to-get-search-log-w","errorCode":null,"errorMessage":"failed to get search log: %w","messagePattern":"failed to get search log: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/slog.go","lineNumber":81,"sourceCode":"\t\tTaskID:    database.Int64ToNullInt64(taskID),\n\t\tSubtaskID: database.Int64ToNullInt64(subtaskID),\n\t})\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"failed to create search log: %w\", err)\n\t}\n\n\tslw.pub.SearchLogAdded(ctx, slLog)\n\n\treturn slLog.ID, nil\n}\n\nfunc (slw *flowSearchLogWorker) GetLog(ctx context.Context, msgID int64) (database.Searchlog, error) {\n\tmsg, err := slw.db.GetFlowSearchLog(ctx, database.GetFlowSearchLogParams{\n\t\tID:     msgID,\n\t\tFlowID: slw.flowID,\n\t})\n\tif err != nil {\n\t\treturn database.Searchlog{}, fmt.Errorf(\"failed to get search log: %w\", err)\n\t}\n\n\treturn msg, nil\n}\n","sourceCodeStart":63,"sourceCodeEnd":86,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/slog.go#L63-L86","documentation":"GetLog wraps any error returned by the database query GetFlowSearchLog (fetching a search-log row by ID and flowID) into a contextual error. The library throws it whenever the underlying DB lookup fails, including the sql.ErrNoRows case where no matching log exists. It preserves the root cause via %w for errors.Is/As inspection.","triggerScenarios":"Calling GetLog(ctx, msgID) on a flowSearchLogWorker when: the msgID does not exist in the search_logs table, the log exists but belongs to a different flow (flowID mismatch), or the database is unreachable/failing.","commonSituations":"Frontend requests a stale or deleted search log ID; worker cache is keyed by flowID but the caller passes an ID from another flow; transient Postgres connection drops or timeouts under load.","solutions":["Verify the msgID actually exists and belongs to the flow via a direct DB query on the search_logs table.","Check errors.Is(err, database.ErrRecordNotFound) (or sql.ErrNoRows) in the caller and treat it as a 404, not a 500.","Confirm the flowID used to create the worker matches the flow that produced the log entry.","Check DB connectivity and migration state (goose migrations applied) if lookups fail across the board."],"exampleFix":"// before\nmsg, err := slw.GetLog(ctx, msgID)\nif err != nil {\n    return fmt.Errorf(\"internal error: %v\", err)\n}\n// after\nmsg, err := slw.GetLog(ctx, msgID)\nif err != nil {\n    if errors.Is(err, sql.ErrNoRows) {\n        return ErrNotFound // surface as 404 to the client\n    }\n    return fmt.Errorf(\"get search log: %w\", err)\n}","handlingStrategy":"try-catch","validationCode":"// before calling GetLog, check the log exists and belongs to the flow\nvar exists bool\nerr := db.QueryRowContext(ctx,\n    `SELECT EXISTS(SELECT 1 FROM search_logs WHERE id=$1 AND flow_id=$2)`,\n    msgID, flowID).Scan(&exists)\nif !exists { return ErrNotFound }","typeGuard":"func IsSearchLogNotFound(err error) bool {\n    return errors.Is(err, sql.ErrNoRows)\n}","tryCatchPattern":"msg, err := worker.GetLog(ctx, msgID)\nif err != nil {\n    if IsSearchLogNotFound(err) {\n        http.Error(w, \"search log not found\", http.StatusNotFound)\n        return\n    }\n    http.Error(w, \"internal error\", http.StatusInternalServerError)\n    return\n}","preventionTips":["Only pass msgIDs obtained from the same flow's log listing endpoints.","Always errors.Is-check the wrapped cause instead of string matching.","Handle sql.ErrNoRows as a 404 path, not a 500.","Keep DB migrations current so lookups never fail on schema drift."],"tags":["database","error-wrapping","not-found"],"backgroundTag":"database-record-not-found","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}