mvanhorn/last30days-skill · error · ValueError

--as-of must be in YYYY-MM-DD format.

Error message

--as-of must be in YYYY-MM-DD format.

What it means

`lib/dates.py:normalize_as_of_date` raises this ValueError when the `--as-of` argument is a non-None string that is empty or only whitespace. The function treats None as 'no date' (returns None) but a blank string as user error: the flag was passed with no usable value. Callers surface it as a CLI argument error.

Source

Thrown at skills/last30days/scripts/lib/dates.py:23


def parse_as_of_date(as_of_date: Optional[str]) -> Optional[str]:
    """Validate and normalize an --as-of date.

    Args:
        as_of_date: Date string in YYYY-MM-DD format.

    Returns:
        Normalized YYYY-MM-DD string, or None when no date was provided.

    Raises:
        ValueError: If the date is not in YYYY-MM-DD format.
    """
    if as_of_date is None:
        return None

    if not as_of_date.strip():
        raise ValueError("--as-of must be in YYYY-MM-DD format.")

    try:
        parsed = datetime.strptime(as_of_date, "%Y-%m-%d").date()
    except ValueError as exc:
        raise ValueError(
            f"Invalid --as-of date: {as_of_date}. Expected YYYY-MM-DD."
        ) from exc

    return parsed.isoformat()


def get_date_range(days: int = 30, as_of_date: Optional[str] = None) -> Tuple[str, str]:
    """Get the date range for the last N days.

    When as_of_date is provided, the range ends at that date instead of today.

    Args:
        days: Number of days to look back.

View on GitHub (pinned to c7460f6114)

Solutions

  1. Omit the `--as-of` flag entirely when you want 'today' behavior (None is accepted and means no as-of override).
  2. If scripting, guard before invoking: only append the flag when the variable is non-empty (`[ -n "$DATE" ] && args+=(--as-of "$DATE")`).
  3. If a date was intended, pass a real `YYYY-MM-DD` value (which then goes through the strptime check for error 22).

Example fix

# before
python3 last30days.py "topic" --as-of "$AS_OF"   # AS_OF unset -> blank string
# after
python3 last30days.py "topic" ${AS_OF:+--as-of "$AS_OF"}
Defensive patterns

Strategy: validation

Validate before calling

def as_of_args(value: str | None) -> list[str]:
    if value is None:
        return []
    if not value.strip():
        raise SystemExit("--as-of must be a YYYY-MM-DD date; pass nothing to use today")
    return ["--as-of", value.strip()]

Try / catch

try:
    normalized = normalize_as_of_date(raw)
except ValueError as exc:
    # treat blank input the same as absent
    if "must be in YYYY-MM-DD" in str(exc):
        normalized = None
    else:
        raise

Prevention

When it happens

Trigger: Running with `--as-of ''`, `--as-of " "`, or a shell expansion that yields an empty string (e.g. `--as-of "$AS_OF"` with the env var unset and `set -u` not in effect).

Common situations: Scripts templating `--as-of $DATE` where DATE failed to populate; CI pipelines passing a computed date that came out empty; wrapping the CLI in another tool that forwards an optional flag even when the value is blank.

Related errors


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