{"record":{"id":"fcdd4e9809fcbd6c","repo":"mvanhorn/last30days-skill","slug":"missing-required-field-field","errorCode":null,"errorMessage":"missing required field '{field}'","messagePattern":"missing required field '(.+?)'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/planner.py","lineNumber":173,"sourceCode":"    \"github\": {\"discussion\", \"link\"},\n    \"grounding\": {\"web\", \"reference\", \"link\"},\n    \"perplexity\": {\"web\", \"reference\", \"analysis\"},\n    \"jobs\": {\"jobs\", \"company_signal\", \"link\"},\n    \"corpus\": {\"reference\", \"analysis\"},\n}\n\n\ndef validate_external_plan(raw: dict) -> None:\n    \"\"\"Validate explicit-plan structure before permissive sanitization.\n\n    Enum-like metadata stays permissive because direct pipeline callers rely on\n    the sanitizer to canonicalize those values.\n    \"\"\"\n    if not isinstance(raw, dict):\n        raise ValueError(\"top-level plan must be an object\")\n    for field in (\"intent\", \"freshness_mode\", \"cluster_mode\", \"subqueries\"):\n        if field not in raw:\n            raise ValueError(f\"missing required field '{field}'\")\n    for field in (\"intent\", \"freshness_mode\", \"cluster_mode\"):\n        if not isinstance(raw[field], str) or not raw[field].strip():\n            raise ValueError(f\"field '{field}' must be a non-empty string\")\n\n    source_weights = raw.get(\"source_weights\")\n    if source_weights is not None and not isinstance(source_weights, dict):\n        raise ValueError(\"field 'source_weights' must be an object when provided\")\n    for source, weight in (source_weights or {}).items():\n        if (\n            not isinstance(source, str)\n            or not source.strip()\n            or isinstance(weight, bool)\n            or not isinstance(weight, (int, float))\n        ):\n            raise ValueError(\"field 'source_weights' must map source names to numbers\")\n    subqueries = raw[\"subqueries\"]\n    if not isinstance(subqueries, list) or not subqueries:\n        raise ValueError(\"field 'subqueries' must be a non-empty array\")","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/planner.py#L155-L191","documentation":"Required-field check in validate_external_plan: the top-level object must contain the four keys 'intent', 'freshness_mode', 'cluster_mode', and 'subqueries'. The first missing one is reported by name. These fields are the minimum skeleton the sanitizer needs to canonicalize a plan; enum values themselves are checked permissively later, but presence is mandatory.","triggerScenarios":"Passing an external plan dict that omits any of the four fields — e.g. only {'intent': 'factual', 'subqueries': [...]} missing freshness_mode/cluster_mode.","commonSituations":"Hand-authored plan JSON missing a metadata field; an LLM-generated plan that skipped cluster_mode; older plan schemas from previous versions that lacked one of the fields; trimming a plan template too aggressively.","solutions":["Add the missing field named in the message — e.g. \"freshness_mode\": \"recent\" and \"cluster_mode\": \"thematic\".","Start from a plan produced by the planner itself (serialize a generated plan) and edit it, so all required fields are present.","Keep a schema checklist: intent, freshness_mode, cluster_mode, subqueries."],"exampleFix":"# before\nplan = {\"intent\": \"factual\", \"freshness_mode\": \"recent\", \"subqueries\": [...]}\n\n# after\nplan = {\"intent\": \"factual\", \"freshness_mode\": \"recent\", \"cluster_mode\": \"thematic\", \"subqueries\": [...]}","handlingStrategy":"validation","validationCode":"REQUIRED = (\"intent\", \"freshness_mode\", \"cluster_mode\", \"subqueries\")\nmissing = [f for f in REQUIRED if f not in plan]\nif missing:\n    raise SystemExit(f\"plan missing fields: {missing}\")","typeGuard":"def has_required_plan_fields(plan: dict) -> bool:\n    return isinstance(plan, dict) and all(f in plan for f in (\"intent\", \"freshness_mode\", \"cluster_mode\", \"subqueries\"))","tryCatchPattern":"try:\n    planner.validate_external_plan(plan)\nexcept ValueError as exc:\n    if \"missing required field\" in str(exc):\n        field = str(exc).split(\"'\")[1]\n        plan.setdefault(field, DEFAULTS[field])\n        planner.validate_external_plan(plan)\n    else:\n        raise","preventionTips":["Keep a DEFAULTS dict for the four required fields and setdefault each before submission.","Generate plans from the planner itself and edit from that template."],"tags":["planner","external-plan","validation","json"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}