mvanhorn/last30days-skill · error · ValueError
subqueries[{index}].weight must be a number when provided
Error message
subqueries[{index}].weight must be a number when provided What it means
Optional per-subquery check: 'weight' may be omitted (None), but if present it must be an int or float and not a bool — the same bool-exclusion trick as source_weights, since Python bools are ints. String numbers, booleans, and null-that-isn't-None-in-Python (e.g. JSON null → None is allowed only by omission semantics; explicit non-numeric values fail) are rejected.
Source
Thrown at skills/last30days/scripts/lib/planner.py:207
subqueries = raw["subqueries"]
if not isinstance(subqueries, list) or not subqueries:
raise ValueError("field 'subqueries' must be a non-empty array")
for index, subquery in enumerate(subqueries):
if not isinstance(subquery, dict):
raise ValueError(f"subqueries[{index}] must be an object")
for field in ("search_query", "ranking_query"):
if not isinstance(subquery.get(field), str) or not subquery[field].strip():
raise ValueError(f"subqueries[{index}].{field} must be a non-empty string")
sources = subquery.get("sources")
if not isinstance(sources, list) or not sources or not all(
isinstance(source, str) and source.strip() for source in sources
):
raise ValueError(f"subqueries[{index}].sources must be a non-empty string array")
weight = subquery.get("weight")
if weight is not None and (
isinstance(weight, bool) or not isinstance(weight, (int, float))
):
raise ValueError(f"subqueries[{index}].weight must be a number when provided")
DEFAULT_INTENT_CAPABILITIES = {
"comparison": {"discussion", "video", "web", "reference", "social", "link", "market"},
"how_to": {"discussion", "video", "web", "reference", "link"},
}
class DrillTargetError(ValueError):
"""Raised when a follow-up target cannot be resolved to a report cluster."""
def __init__(self, target: str, clusters: list[schema.Cluster]) -> None:
candidates = ", ".join(
f"{index}. {cluster.title}"
for index, cluster in enumerate(clusters, start=1)
) or "(no clusters in the cached report)"
super().__init__(f"No cluster matched {target!r}. Available clusters: {candidates}")
View on GitHub (pinned to c7460f6114)
Solutions
- Use bare numbers: "weight": 2 or "weight": 0.5.
- Cast CLI/env-provided weights with float() before embedding.
- Omit the key entirely for default weighting.
Example fix
# before
{"search_query": "q", "ranking_query": "q", "sources": ["reddit"], "weight": "2"}
# after
{"search_query": "q", "ranking_query": "q", "sources": ["reddit"], "weight": 2} Defensive patterns
Strategy: type-guard
Validate before calling
w = q.get("weight")
if isinstance(w, str):
q["weight"] = float(w)
if isinstance(w, bool) or w is None and "weight" in q:
q.pop("weight", None) # booleans/null mean 'unweighted' -> omit Type guard
def is_optional_numeric_weight(v) -> bool:
return v is None or (isinstance(v, (int, float)) and not isinstance(v, bool)) Prevention
- Omit weight for default weighting instead of passing true/1/null.
- Cast string weights with float() at the boundary (CLI args arrive as strings).
When it happens
Trigger: A subquery with "weight": "2", "weight": true, or "weight": [1]. Omitting the key or setting null (None) is fine.
Common situations: Quoted weights from JSON templating; LLMs emitting true to mean 'weighted'; weight as a string because it came from a CLI argument.
Related errors
- top-level plan must be an object
- missing required field '{field}'
- field '{field}' must be a non-empty string
- field 'source_weights' must be an object when provided
- field 'source_weights' must map source names to numbers
AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15).
Data as JSON: /api/errors/f85af8e07bfce9ad.
Report an issue: GitHub.