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

  1. Use bare numbers: "weight": 2 or "weight": 0.5.
  2. Cast CLI/env-provided weights with float() before embedding.
  3. 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

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


AI-assisted analysis of mvanhorn/last30days-skill@c7460f6114 (2026-08-15). Data as JSON: /api/errors/f85af8e07bfce9ad. Report an issue: GitHub.