{"record":{"id":"4986cca5346f554f","repo":"koala73/worldmonitor","slug":"query-is-required","errorCode":null,"errorMessage":"query is required","messagePattern":"query is required","errorType":"validation","errorClass":"ValidationError","httpStatus":400,"severity":"error","filePath":"server/worldmonitor/intelligence/v1/search-sec-filings.ts","lineNumber":24,"sourceCode":"\nimport type {\n  ServerContext,\n  SearchSecFilingsRequest,\n  SearchSecFilingsResponse,\n} from '../../../../src/generated/server/worldmonitor/intelligence/v1/service_server';\nimport { ValidationError } from '../../../../src/generated/server/worldmonitor/intelligence/v1/service_server';\nimport { isEdgarIsoDate, normalizeEdgarForms, searchEdgarFullText } from '../../../_shared/sec-edgar';\n\nconst DEFAULT_LIMIT = 10;\nconst MAX_LIMIT = 25;\n\nexport async function searchSecFilings(\n  _ctx: ServerContext,\n  req: SearchSecFilingsRequest,\n): Promise<SearchSecFilingsResponse> {\n  const query = req.query?.trim();\n  if (!query) {\n    throw new ValidationError([{ field: 'query', description: 'query is required' }]);\n  }\n\n  // Fail closed on malformed filters. Silently dropping one WIDENS the result\n  // set, so a typo'd date range would return unrelated filings while the caller\n  // believes the range was applied.\n  const formsNormalized = normalizeEdgarForms(req.forms);\n  const startDateValid = !req.startDate || isEdgarIsoDate(req.startDate);\n  const endDateValid = !req.endDate || isEdgarIsoDate(req.endDate);\n  const violations = [\n    ...(formsNormalized === null\n      ? [{ field: 'forms', description: 'forms must be a comma-separated form list such as \"8-K\" or \"10-K,10-Q\"' }]\n      : []),\n    ...(!startDateValid\n      ? [{ field: 'start_date', description: 'start_date must be YYYY-MM-DD' }]\n      : []),\n    ...(!endDateValid\n      ? [{ field: 'end_date', description: 'end_date must be YYYY-MM-DD' }]\n      : []),","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/koala73/worldmonitor/blob/eeab0a219fce0f02a00603b532dbae9041b934ac/server/worldmonitor/intelligence/v1/search-sec-filings.ts#L6-L42","documentation":"searchSecFilings throws ValidationError (field 'query') when req.query is empty after trimming — the EDGAR full-text search requires a query string. The check runs before filter validation, so an empty query is reported even if forms/dates are also malformed.","triggerScenarios":"Calling /api/intelligence/v1/search-sec-filings with query omitted or whitespace; a search box submitted empty; programmatic calls where the query variable failed to populate (undefined coerced to '').","commonSituations":"Missing client-side required-field validation; script iterating search terms where one iteration's term is blank; parameter sent under a different name (q vs query) leaving query empty.","solutions":["Require a non-blank query in the client before calling","Skip iteration when the search term is empty instead of calling the API","Verify the request body uses the exact proto field name 'query'"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"const query = rawQuery?.trim();\nif (!query) {\n  throw new ClientError('A search query is required');\n}","typeGuard":"function isQueryViolation(body: unknown): boolean {\n  const v = (body as { violations?: { field?: string }[] })?.violations;\n  return Array.isArray(v) && v.some((x) => x.field === 'query');\n}","tryCatchPattern":"try {\n  await searchSecFilings({ query });\n} catch (e) {\n  if (e instanceof HttpError && e.status === 400 && isQueryViolation(e.body)) {\n    return focusSearchBox();\n  }\n  throw e;\n}","preventionTips":["Require a non-blank query client-side; EDGAR full-text search has no empty-query mode","Skip blank terms when iterating search-term lists programmatically","Use the proto field name 'query' — sending 'q' leaves it empty and hits this violation first"],"tags":["intelligence","sec","edgar","validation","missing-parameter"],"backgroundTag":"missing-required-argument","analyzedSha":"eeab0a219fce0f02a00603b532dbae9041b934ac","analyzedAt":"2026-08-21T16:51:25.751Z","contentChangedAt":"2026-08-21T16:51:25.751Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}