{"record":{"id":"a0d8554c1b756ee3","repo":"decolua/9router","slug":"missing-required-field-url","errorCode":null,"errorMessage":"Missing required field: url","messagePattern":"Missing required field: url","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"src/sse/handlers/fetch.js","lineNumber":70,"sourceCode":"  if (settings.requireApiKey) {\n    if (!apiKey) {\n      log.warn(\"AUTH\", \"Missing API key (requireApiKey=true)\");\n      return errorResponse(HTTP_STATUS.UNAUTHORIZED, \"Missing API key\");\n    }\n    const valid = await isValidApiKey(apiKey);\n    if (!valid) {\n      log.warn(\"AUTH\", \"Invalid API key (requireApiKey=true)\");\n      return errorResponse(HTTP_STATUS.UNAUTHORIZED, \"Invalid API key\");\n    }\n  }\n\n  if (!providerInput || typeof providerInput !== \"string\") {\n    log.warn(\"FETCH\", \"Missing provider/model\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing required field: provider (or model)\");\n  }\n\n  if (!targetUrl || typeof targetUrl !== \"string\") {\n    log.warn(\"FETCH\", \"Missing url\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing required field: url\");\n  }\n\n  // Validate URL format\n  try {\n    new URL(targetUrl);\n  } catch {\n    log.warn(\"FETCH\", \"Invalid URL\", { url: targetUrl });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Invalid URL format\");\n  }\n\n  // SSRF guard: reject internal/private/metadata targets\n  try {\n    assertPublicUrl(targetUrl);\n  } catch (err) {\n    log.warn(\"FETCH\", \"Blocked URL\", { url: targetUrl });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, err.message);\n  }","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/fetch.js#L52-L88","documentation":"The /v1 web-fetch endpoint requires a `url` field in the JSON body naming the page to extract. handleFetch reads body.url and returns HTTP 400 'Missing required field: url' when it is absent, null, empty, or not a string. This is an early input-validation gate before any URL parsing, SSRF checks, or provider dispatch.","triggerScenarios":"POSTing to the fetch endpoint with a body that omits `url`, sets it to null/undefined, sends an empty string, or sends a non-string (number, object). Note the handler also accepts `provider` or `model` for the provider field, but `url` itself has no alias.","commonSituations":"Client forgot the url field; a UI bug sends only {model}; a wrapper script forwards a payload where the URL lives under a different key (link, target, href); JSON serialization dropped the field because it was undefined.","solutions":["Add a string `url` field to the request body, e.g. {\"model\":\"jina\",\"url\":\"https://example.com\"}","If your URL is stored under another key, rename it to `url` before sending - there is no alias for this field","Confirm the body is valid JSON with Content-Type: application/json so request.json() parses all fields"],"exampleFix":"// before\nawait fetch('/v1/fetch', { method: 'POST', body: JSON.stringify({ model: 'jina' }) });\n// after\nawait fetch('/v1/fetch', { method: 'POST', body: JSON.stringify({ model: 'jina', url: 'https://example.com/page' }) });","handlingStrategy":"validation","validationCode":"function validateFetchRequest(body) {\n  if (!body || typeof body.url !== 'string' || body.url.length === 0) {\n    throw new TypeError(\"request body must include a non-empty string 'url' field\");\n  }\n  return body;\n}","typeGuard":"function hasUrl(body) {\n  return typeof body === 'object' && body !== null && typeof body.url === 'string' && body.url.length > 0;\n}","tryCatchPattern":"try {\n  const res = await fetch(endpoint, { method: 'POST', body: JSON.stringify(payload) });\n  if (res.status === 400 && (await res.text()).includes('Missing required field: url')) {\n    console.error('Payload missing url field:', payload);\n  }\n} catch (err) { /* network-level failure */ }","preventionTips":["Always include url in the fetch payload; build payloads from a single constructor function so the field cannot be dropped","Add a client-side schema check (or zod) before sending: url must be a non-empty string","Do not name the field link/href/target - the endpoint only reads `url`"],"tags":["http-400","input-validation","missing-field","web-fetch"],"backgroundTag":"missing-required-field","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}