{"record":{"id":"d470356649f06e9b","repo":"mvanhorn/last30days-skill","slug":"as-of-must-be-in-yyyy-mm-dd-format","errorCode":null,"errorMessage":"--as-of must be in YYYY-MM-DD format.","messagePattern":"--as-of must be in YYYY-MM-DD format\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"skills/last30days/scripts/lib/dates.py","lineNumber":23,"sourceCode":"\n\ndef parse_as_of_date(as_of_date: Optional[str]) -> Optional[str]:\n    \"\"\"Validate and normalize an --as-of date.\n\n    Args:\n        as_of_date: Date string in YYYY-MM-DD format.\n\n    Returns:\n        Normalized YYYY-MM-DD string, or None when no date was provided.\n\n    Raises:\n        ValueError: If the date is not in YYYY-MM-DD format.\n    \"\"\"\n    if as_of_date is None:\n        return None\n\n    if not as_of_date.strip():\n        raise ValueError(\"--as-of must be in YYYY-MM-DD format.\")\n\n    try:\n        parsed = datetime.strptime(as_of_date, \"%Y-%m-%d\").date()\n    except ValueError as exc:\n        raise ValueError(\n            f\"Invalid --as-of date: {as_of_date}. Expected YYYY-MM-DD.\"\n        ) from exc\n\n    return parsed.isoformat()\n\n\ndef get_date_range(days: int = 30, as_of_date: Optional[str] = None) -> Tuple[str, str]:\n    \"\"\"Get the date range for the last N days.\n\n    When as_of_date is provided, the range ends at that date instead of today.\n\n    Args:\n        days: Number of days to look back.","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/mvanhorn/last30days-skill/blob/c7460f6114449ddfe6ea3fc2f23c3d910c0e740c/skills/last30days/scripts/lib/dates.py#L5-L41","documentation":"`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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Omit the `--as-of` flag entirely when you want 'today' behavior (None is accepted and means no as-of override).","If scripting, guard before invoking: only append the flag when the variable is non-empty (`[ -n \"$DATE\" ] && args+=(--as-of \"$DATE\")`).","If a date was intended, pass a real `YYYY-MM-DD` value (which then goes through the strptime check for error 22)."],"exampleFix":"# before\npython3 last30days.py \"topic\" --as-of \"$AS_OF\"   # AS_OF unset -> blank string\n# after\npython3 last30days.py \"topic\" ${AS_OF:+--as-of \"$AS_OF\"}","handlingStrategy":"validation","validationCode":"def as_of_args(value: str | None) -> list[str]:\n    if value is None:\n        return []\n    if not value.strip():\n        raise SystemExit(\"--as-of must be a YYYY-MM-DD date; pass nothing to use today\")\n    return [\"--as-of\", value.strip()]","typeGuard":null,"tryCatchPattern":"try:\n    normalized = normalize_as_of_date(raw)\nexcept ValueError as exc:\n    # treat blank input the same as absent\n    if \"must be in YYYY-MM-DD\" in str(exc):\n        normalized = None\n    else:\n        raise","preventionTips":["Only append --as-of to your command when the date variable is truthy.","Treat blank as 'omit the flag' at the wrapper layer, since the engine treats blank as an error by design."],"tags":["cli","dates","validation","argument-error"],"backgroundTag":null,"analyzedSha":"c7460f6114449ddfe6ea3fc2f23c3d910c0e740c","analyzedAt":"2026-08-15T03:34:49.540Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}