{"record":{"id":"fd021b0a96b4524b","repo":"nexu-io/open-design","slug":"subquery-weight-must-be-positive-got-self-weight","errorCode":null,"errorMessage":"SubQuery weight must be positive, got {self.weight}","messagePattern":"SubQuery weight must be positive, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"design-templates/last30days/scripts/lib/schema.py","lineNumber":55,"sourceCode":"    rerank_model: str\n    x_search_backend: Literal[\"xai\", \"bird\"] | None = None\n\n\n@dataclass(frozen=True)\nclass SubQuery:\n    \"\"\"Planner-emitted retrieval unit.\"\"\"\n\n    label: str\n    search_query: str\n    ranking_query: str\n    sources: list[str]\n    weight: float = 1.0\n\n    def __post_init__(self) -> None:\n        if not self.sources:\n            raise ValueError(\"SubQuery must have at least one source\")\n        if self.weight <= 0:\n            raise ValueError(f\"SubQuery weight must be positive, got {self.weight}\")\n\n\n@dataclass\nclass QueryPlan:\n    \"\"\"Planner output.\"\"\"\n\n    intent: str\n    freshness_mode: str\n    cluster_mode: str\n    raw_topic: str\n    subqueries: list[SubQuery]\n    source_weights: dict[str, float]\n    notes: list[str] = field(default_factory=list)\n\n\n@dataclass\nclass SourceItem:\n    \"\"\"Generic normalized evidence item.\"\"\"","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/design-templates/last30days/scripts/lib/schema.py#L37-L73","documentation":"Second invariant in SubQuery.__post_init__: weight must be > 0. Weight is used downstream for RRF-style fusion and ranking; a zero or negative weight would silently drop or invert the subquery's contribution, so construction fails loudly instead.","triggerScenarios":"Constructing SubQuery(..., weight=0) or a negative weight. Reached when the planner emits a weight of 0, when a normalization step divides by a sum that produced 0, or when a default of 0 was used instead of the dataclass default 1.0.","commonSituations":"Planner JSON with 'weight': 0. Weight normalization that scales all weights to 0. Test fixture setting weight=0 by accident. Float parse of '0.0' string.","solutions":["Ensure the planner emits strictly positive weights (e.g. >= 0.1).","After any weight normalization, clamp each weight to a small positive floor before constructing SubQuery.","Omit the weight argument to inherit the default 1.0."],"exampleFix":"# before\nSubQuery(label='t', search_query='q', ranking_query='q', sources=['x'], weight=0.0)\n\n# after\nw = max(raw_weight, 0.1)\nSubQuery(label='t', search_query='q', ranking_query='q', sources=['x'], weight=w)","handlingStrategy":"validation","validationCode":"def build_subquery(label, search_query, ranking_query, sources, weight=1.0):\n    if not sources:\n        raise ValueError(f\"subquery {label!r} needs at least one source\")\n    if weight <= 0:\n        raise ValueError(f\"subquery {label!r} weight must be > 0, got {weight}\")\n    return SubQuery(label, search_query, ranking_query, list(sources), weight=weight)","typeGuard":"def is_positive_weight(w) -> bool:\n    return isinstance(w, (int, float)) and w > 0","tryCatchPattern":"null","preventionTips":["Clamp normalized weights to a small positive floor (e.g. max(w, 0.1)) before constructing SubQuery.","Validate the planner weight field is a positive number at parse time.","Default to 1.0 when the planner omits weight."],"tags":["validation","dataclass","ranking","invariant"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}