decolua/9router · warning

Missing required field: query

Error message

Missing required field: query

What it means

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.

Source

Thrown at src/sse/handlers/search.js:67

  if (settings.requireApiKey) {
    if (!apiKey) {
      log.warn("AUTH", "Missing API key (requireApiKey=true)");
      return errorResponse(HTTP_STATUS.UNAUTHORIZED, "Missing API key");
    }
    const valid = await isValidApiKey(apiKey);
    if (!valid) {
      log.warn("AUTH", "Invalid API key (requireApiKey=true)");
      return errorResponse(HTTP_STATUS.UNAUTHORIZED, "Invalid API key");
    }
  }

  if (!providerInput || typeof providerInput !== "string") {
    log.warn("SEARCH", "Missing provider/model");
    return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing required field: provider (or model)");
  }

  if (!query || typeof query !== "string" || !query.trim()) {
    log.warn("SEARCH", "Missing query");
    return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing required field: query");
  }

  // Combo expansion: providerInput may be a combo name → run fallback/round-robin across providers
  const combos = await getCombos();
  const comboModels = getComboModelsFromData(providerInput, combos);
  if (comboModels) {
    const comboStrategies = settings.comboStrategies || {};
    const comboStrategy = comboStrategies[providerInput]?.fallbackStrategy || settings.comboStrategy || "fallback";
    const comboStickyLimit = settings.comboStickyRoundRobinLimit;
    log.info("SEARCH", `Combo "${providerInput}" with ${comboModels.length} providers (strategy: ${comboStrategy}, sticky: ${comboStickyLimit})`);
    return handleComboChat({
      body,
      models: comboModels,
      handleSingleModel: (b, m) => handleSingleProviderSearch(b, m, request, apiKey, settings),
      log,
      comboName: providerInput,
      comboStrategy,

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Include a non-empty trimmed `query` string in the request body.
  2. Add client-side validation: reject empty/whitespace-only query before sending.
  3. Confirm the client targets the search endpoint shape ({provider, query}) not the chat shape ({model, messages}).
  4. If building the body dynamically, log it before fetch to catch undefined interpolations.

Example fix

// before
const body = { provider: 'brave', query: userInput }; // userInput may be ''
// after
if (!userInput?.trim()) throw new Error('query required');
const body = { provider: 'brave', query: userInput.trim() };
Defensive patterns

Strategy: validation

Validate before calling

if (typeof body.query !== 'string' || !body.query.trim()) {
  throw new TypeError('query is required and must be a non-whitespace string');
}

Type guard

function hasQuery(b) { return typeof b?.query === 'string' && b.query.trim().length > 0; }

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/82fde62fdc3acbc1. Report an issue: GitHub.