{"record":{"id":"82fde62fdc3acbc1","repo":"decolua/9router","slug":"missing-required-field-query","errorCode":null,"errorMessage":"Missing required field: query","messagePattern":"Missing required field: query","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"src/sse/handlers/search.js","lineNumber":67,"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(\"SEARCH\", \"Missing provider/model\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing required field: provider (or model)\");\n  }\n\n  if (!query || typeof query !== \"string\" || !query.trim()) {\n    log.warn(\"SEARCH\", \"Missing query\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing required field: query\");\n  }\n\n  // Combo expansion: providerInput may be a combo name → run fallback/round-robin across providers\n  const combos = await getCombos();\n  const comboModels = getComboModelsFromData(providerInput, combos);\n  if (comboModels) {\n    const comboStrategies = settings.comboStrategies || {};\n    const comboStrategy = comboStrategies[providerInput]?.fallbackStrategy || settings.comboStrategy || \"fallback\";\n    const comboStickyLimit = settings.comboStickyRoundRobinLimit;\n    log.info(\"SEARCH\", `Combo \"${providerInput}\" with ${comboModels.length} providers (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);\n    return handleComboChat({\n      body,\n      models: comboModels,\n      handleSingleModel: (b, m) => handleSingleProviderSearch(b, m, request, apiKey, settings),\n      log,\n      comboName: providerInput,\n      comboStrategy,","sourceCodeStart":49,"sourceCodeEnd":85,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/search.js#L49-L85","documentation":"After the provider/model check, handleSearch requires a non-empty, non-whitespace `query` string. This error means the search body was well-formed enough to name a provider but carried no usable search text. It is a 400 BAD_REQUEST returned synchronously before any provider or credential lookup.","triggerScenarios":"POST to the search endpoint with body.query missing, non-string (null/number/object), an empty string, or a whitespace-only string like '   '. Provider is present and valid, so validation fails only at the query step.","commonSituations":"A UI sending the request before the user typed a query; form submit handlers firing on empty input; clients reusing a chat-completion body (messages array) against the search endpoint; template literals interpolating an undefined variable into query.","solutions":["Include a non-empty trimmed `query` string in the request body.","Add client-side validation: reject empty/whitespace-only query before sending.","Confirm the client targets the search endpoint shape ({provider, query}) not the chat shape ({model, messages}).","If building the body dynamically, log it before fetch to catch undefined interpolations."],"exampleFix":"// before\nconst body = { provider: 'brave', query: userInput }; // userInput may be ''\n// after\nif (!userInput?.trim()) throw new Error('query required');\nconst body = { provider: 'brave', query: userInput.trim() };","handlingStrategy":"validation","validationCode":"if (typeof body.query !== 'string' || !body.query.trim()) {\n  throw new TypeError('query is required and must be a non-whitespace string');\n}","typeGuard":"function hasQuery(b) { return typeof b?.query === 'string' && b.query.trim().length > 0; }","tryCatchPattern":null,"preventionTips":["Trim and check query length in UI before enabling submit.","Share one request schema between chat and search clients to avoid shape confusion.","Log outgoing bodies in dev to catch undefined interpolations."],"tags":["http-400","validation","web-search","empty-input"],"backgroundTag":"missing-required-field","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}