{"record":{"id":"ffcf6f31aebd9daf","repo":"vxcontrol/pentagi","slug":"failed-to-get-screenshot-w","errorCode":null,"errorMessage":"failed to get screenshot: %w","messagePattern":"failed to get screenshot: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/pkg/controller/screenshot.go","lineNumber":58,"sourceCode":"\t\tName:      database.SanitizeUTF8(name),\n\t\tUrl:       database.SanitizeUTF8(url),\n\t\tFlowID:    sw.flowID,\n\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 screenshot: %w\", err)\n\t}\n\n\tsw.pub.ScreenshotAdded(ctx, screenshot)\n\n\treturn screenshot.ID, nil\n}\n\nfunc (sw *flowScreenshotWorker) GetScreenshot(ctx context.Context, screenshotID int64) (database.Screenshot, error) {\n\tscreenshot, err := sw.db.GetScreenshot(ctx, screenshotID)\n\tif err != nil {\n\t\treturn database.Screenshot{}, fmt.Errorf(\"failed to get screenshot: %w\", err)\n\t}\n\n\treturn screenshot, nil\n}\n","sourceCodeStart":40,"sourceCodeEnd":63,"githubUrl":"https://github.com/vxcontrol/pentagi/blob/ea665308baaff015b226f308438a68d929d0f29b/backend/pkg/controller/screenshot.go#L40-L63","documentation":"GetScreenshot fetches a single screenshot row by ID via db.GetScreenshot and wraps any query failure as \"failed to get screenshot: %w\". Note this fires for ALL database errors including pgx's no-rows condition — a genuinely missing screenshot ID produces this same wrapped error rather than a distinct not-found sentinel.","triggerScenarios":"Calling GetScreenshot(ctx, screenshotID) with a database error: connection failure, context cancellation, or the ID not existing in the screenshots table (sql.ErrNoRows / pgx.ErrNoRows wrapped).","commonSituations":"UI requesting a screenshot that was deleted or belongs to another flow; stale ID after data retention cleanup; DB connectivity issues; typo'd or forged screenshot ID from a client.","solutions":["Unwrap and check for pgx.ErrNoRows / sql.ErrNoRows to distinguish not-found from real failures.","Verify the screenshot ID exists (e.g. query the screenshots table directly).","Check DB connectivity if many screenshots fail at once.","Extend the caller's context timeout if the query is timing out."],"exampleFix":"// before: all failures treated the same\nshot, err := sw.GetScreenshot(ctx, id)\n\n// after: distinguish not-found\nshot, err := sw.GetScreenshot(ctx, id)\nif err != nil {\n    if errors.Is(err, pgx.ErrNoRows) {\n        return nil, ErrScreenshotNotFound\n    }\n    return nil, err\n}","handlingStrategy":"type-guard","validationCode":"// check existence first if your query layer exposes it\nvar exists bool\nerr := db.QueryRow(\"SELECT EXISTS(SELECT 1 FROM screenshots WHERE id=$1)\", id).Scan(&exists)","typeGuard":"func isScreenshotNotFound(err error) bool {\n    return errors.Is(err, pgx.ErrNoRows) || errors.Is(err, sql.ErrNoRows)\n}","tryCatchPattern":"shot, err := sw.GetScreenshot(ctx, id)\nif err != nil {\n    if isScreenshotNotFound(err) {\n        return nil, ErrScreenshotNotFound // 404, not 500\n    }\n    return nil, err\n}","preventionTips":["Always errors.Is-check for ErrNoRows — this wrapper hides not-found inside a generic message.","Validate client-supplied screenshot IDs before lookup.","Account for retention/cleanup jobs deleting old screenshots.","Monitor bulk failures as DB connectivity problems, not user errors."],"tags":["database","go","screenshot","not-found"],"backgroundTag":"database-query-failed","analyzedSha":"ea665308baaff015b226f308438a68d929d0f29b","analyzedAt":"2026-09-01T14:16:31.421Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}