Skip to content

fix: log _load_last_report_cache failure to stderr instead of silent swallow (#787)#788

Open
23241a6749 wants to merge 2 commits into
mvanhorn:mainfrom
23241a6749:fix/cache-read-silent-swallow
Open

fix: log _load_last_report_cache failure to stderr instead of silent swallow (#787)#788
23241a6749 wants to merge 2 commits into
mvanhorn:mainfrom
23241a6749:fix/cache-read-silent-swallow

Conversation

@23241a6749

Copy link
Copy Markdown
Contributor

Summary

_load_last_report_cache() caught all Exception and silently returned None (cache miss) with zero diagnostic output. If the cache file at ~/.config/last30days/last-report.json is corrupted, truncated, or version-mismatched, users had no way to know why the cache was being regenerated on every run — wasted token spend and lost performance.

Change

last30days.py:762-763 — replaced except Exception: return None with:

except Exception as exc:
    sys.stderr.write(f"[last30days] Cache read failed, regenerating: {exc}\n")
    return None
``"

The function still returns `None` (cache missregenerate), but now emits a diagnostic so users can identify and fix the root cause.

Fixes #787.

…swallow

The _load_last_report_cache function caught all exceptions and returned
None (cache miss) without any diagnostic output. If the cache file is
corrupted, truncated, or contains unexpected data, users had no way
to know why the cache was being regenerated on every run.

Now logs the exception to stderr before falling through to the cache-miss
path, so automated and interactive users alike can diagnose the issue.

Fixes mvanhorn#787.
@greptile-apps

greptile-apps Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR converts a silent exception swallow in _load_last_report_cache() into a visible stderr diagnostic, helping users identify why the cache is being regenerated on every run. The behavioral contract is unchanged — the function still returns None on any error, triggering a cache miss and regeneration.

  • last30days.py: Binds the caught exception to exc and emits [last30days] Cache read failed, regenerating: {exc} to stderr before returning None. Uses the same sys.stderr.write() pattern already established in the file (e.g., the Python version check at line 28).
  • uv.lock: Reflects the 3.11.0 → 3.11.1 patch version bump already present in pyproject.toml.

Confidence Score: 5/5

Safe to merge — a two-line addition that adds observability without changing any functional behavior.

The change is minimal and targeted: it binds the caught exception and writes a single diagnostic line to stderr before the existing return None. sys is already imported and sys.stderr.write() is used elsewhere in the file for the same purpose. No new code paths, no state changes, no risk of regression.

No files require special attention.

Important Files Changed

Filename Overview
skills/last30days/scripts/last30days.py Two-line change: binds caught exception as exc and writes a diagnostic to stderr before returning None; no behavioral change, follows existing sys.stderr.write() pattern in the file.
uv.lock Auto-generated lock file update reflecting the 3.11.0 → 3.11.1 version bump in pyproject.toml.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[_load_last_report_cache called] --> B[Open & parse cache JSON]
    B --> C{Parse OK?}
    C -- yes --> D[Validate payload / entity_reports]
    D --> E{Valid?}
    E -- yes --> F[Return cached report tuple]
    E -- no --> G[Return None\ncache miss]
    C -- no --> H["BEFORE: silent except Exception: return None"]
    C -- no --> I["AFTER: sys.stderr.write diagnostic + return None"]
    H --> J[Caller regenerates report\nno feedback to user]
    I --> K["stderr: [last30days] Cache read failed, regenerating: exc"]
    K --> L[Caller regenerates report\nuser sees root cause]
    style H fill:#fcc,stroke:#c00
    style I fill:#cfc,stroke:#090
    style K fill:#cfc,stroke:#090
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[_load_last_report_cache called] --> B[Open & parse cache JSON]
    B --> C{Parse OK?}
    C -- yes --> D[Validate payload / entity_reports]
    D --> E{Valid?}
    E -- yes --> F[Return cached report tuple]
    E -- no --> G[Return None\ncache miss]
    C -- no --> H["BEFORE: silent except Exception: return None"]
    C -- no --> I["AFTER: sys.stderr.write diagnostic + return None"]
    H --> J[Caller regenerates report\nno feedback to user]
    I --> K["stderr: [last30days] Cache read failed, regenerating: exc"]
    K --> L[Caller regenerates report\nuser sees root cause]
    style H fill:#fcc,stroke:#c00
    style I fill:#cfc,stroke:#090
    style K fill:#cfc,stroke:#090
Loading

Reviews (2): Last reviewed commit: "chore: update uv.lock for v3.11.1" | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant