{"record":{"id":"617646a331fb7243","repo":"lissy93/web-check","slug":"url-is-missing-from-querystringparameters","errorCode":null,"errorMessage":"URL is missing from queryStringParameters","messagePattern":"URL is missing from queryStringParameters","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/screenshot.js","lineNumber":73,"sourceCode":"    });\n    const page = await browser.newPage();\n    await page.emulateMediaFeatures([{ name: 'prefers-color-scheme', value: 'dark' }]);\n    page.setDefaultNavigationTimeout(8000);\n    await page.goto(targetUrl, { waitUntil: 'domcontentloaded' });\n    await page.evaluate(() => {\n      if (!document.querySelector('body')) {\n        throw new Error('No body element found on the page');\n      }\n    });\n    const buffer = await page.screenshot();\n    return buffer.toString('base64');\n  } finally {\n    if (browser) await browser.close().catch(() => {});\n  }\n};\n\nconst screenshotHandler = async (targetUrl) => {\n  if (!targetUrl) throw new Error('URL is missing from queryStringParameters');\n  try {\n    new URL(targetUrl);\n  } catch {\n    throw new Error('URL provided is invalid');\n  }\n\n  log.debug(`request received: ${targetUrl}`);\n  try {\n    return { image: await directChromiumScreenshot(targetUrl) };\n  } catch (directError) {\n    log.warn(`direct chromium failed, falling back to puppeteer: ${directError.message}`);\n  }\n  try {\n    return { image: await puppeteerScreenshot(targetUrl) };\n  } catch (error) {\n    if (/ENOENT|Browser was not found|Could not find Chromium/i.test(error.message)) {\n      return { skipped: error.message };\n    }","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/lissy93/web-check/blob/af1a97759fc8bcc43c876c94f2ccb018ce215f90/api/screenshot.js#L55-L91","documentation":"screenshotHandler requires the target URL as its first argument; when the argument is falsy it throws before any validation runs. The name references AWS API Gateway's queryStringParameters object, indicating this handler is wired to a ?url= query parameter that was absent from the request.","triggerScenarios":"GET /api/screenshot with no ?url parameter; the integration/handler mapping fails to extract queryStringParameters.url and passes undefined.","commonSituations":"Frontend forgetting to append the query param, serverless function URL vs API Gateway param-shape mismatch, or env-specific routing that drops query strings.","solutions":["Add ?url=<full URL including scheme> to the request","Check the request mapping: confirm the param is read from the correct location (req.query.url vs event.queryStringParameters.url)","Return a 400 with guidance from your wrapper when the param is missing instead of letting it bubble as 500"],"exampleFix":"// before\nfetch('/api/screenshot'); // 500: URL is missing from queryStringParameters\n\n// after\nfetch(`/api/screenshot?url=${encodeURIComponent('https://example.com')}`);","handlingStrategy":"validation","validationCode":"const urlParam = req.query.url;\nif (!urlParam) return res.status(400).json({ error: 'url query parameter is required' });\nconst image = await screenshotHandler(urlParam);","typeGuard":"const hasUrlParam = (q) => Object.prototype.hasOwnProperty.call(q, 'url') && typeof q.url === 'string' && q.url.length > 0;","tryCatchPattern":"try { await screenshotHandler(q.url); }\ncatch (e) {\n  if (/missing from queryStringParameters/.test(e.message)) return badRequest('add ?url=...');\n  throw e;\n}","preventionTips":["Validate required query params in a shared request guard before handlers run","Return 400, not 500, for caller mistakes","Add contract tests hitting the endpoint without params to catch wiring regressions"],"tags":["validation","query-parameter","screenshot","api"],"backgroundTag":"missing-required-parameter","analyzedSha":"af1a97759fc8bcc43c876c94f2ccb018ce215f90","analyzedAt":"2026-08-27T11:44:27.410Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}