[BUG]/insights generates empty report — no AI insights produced (facets directory never created)

Status Open
Maintainer reply None cached
Activity 4 comments · opened Jun 22, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Running /insights produces a report with raw stats (tool counts, response times, languages) but all AI-generated sections show "No data":

  • What You Wanted
  • Session Types
  • What Helped Most
  • Outcomes
  • Primary Friction Types
  • Inferred Satisfaction

Root cause observed: The facets directory referenced in the report (~/.claude/usage-data/facets) is never created. Without per-session facets, the synthesis step has nothing to work from.

Reproduced: Twice in the same session — same result both times. The insights data passed to the report is {}.

Environment:

  • Platform: Windows 11
  • Shell: PowerShell / Git Bash
  • Sessions analyzed: 76 of 80 total
  • Date range: 2026-05-24 to 2026-06-22

What does work: Session-meta files are all present and the stats derived from them (tool usage, line counts, response time histogram, time-of-day breakdown) render correctly in the report.

What Should Happen?

The /insights command should analyze session transcripts, populate the facets directory with per-session AI analysis, and produce a report where all sections contain data — including "What You Wanted", "Outcomes", "Primary Friction Types", and "Inferred Satisfaction".

Error Messages/Logs

Steps to Reproduce

  1. Run /insights in Claude Code (Windows 11, PowerShell)
  2. Open the generated HTML report at ~/.claude/usage-data/report-*.html
  3. All AI-generated sections show "No data"
  4. Check ~/.claude/usage-data/ — the facets/ directory is never created
  5. Reproduced twice consecutively with identical results

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

! claude --version

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

PowerShell

Additional Information

_No response_

View original on GitHub ↗

4 Comments

thlehmann-ionos · 1 month ago

Possibly related: #64275

bradfeld · 29 days ago

Root cause, from decompiling the 2.1.220 bundle and diffing it against 2.1.185 (the last version that produced facets on my machine).

tl;dr — facet extraction treats an API-error response as "the model returned no JSON" and returns null down a path that logs nothing. Nothing throws, so --debug shows nothing, and the report renders _No insights generated_ as though there were simply nothing to report.

The bug

In the facet-extraction function (vLy in the 2.1.220 bundle; minified names are version-specific, the surrounding code is the identifier):

let o = await Fft({
  systemPrompt: fp([]),
  userPrompt: n,
  options: {
    model: Rep(),            // -> ST(), the Opus selector
    querySource: "insights",
    maxOutputTokensOverride: 4096,
    agentContext: hb()
  }
});
let s = Jc(o.message.content).match(/\{[\s\S]*\}/);
if (!s) return null;         // <-- API error message lands here. Silent.
let a = Ut(s[0]);
if (!Mep(a)) return null;    // <-- also silent
return { ...a, session_id: t };

with the only logging branch being:

catch (r) { return w(`Facet extraction failed: ${yn(r).message}`, {level:"error"}), null }

Fft returns an API error as a message object rather than throwing. Its content is error text, contains no {...}, the regex misses, if (!s) return null fires, and the catch is never reached.

Evidence this is a missing check rather than a regression

The sibling helper in the same module makes the same Fft({querySource:"insights", ...}) call, and 2.1.220 added the guard that vLy still lacks:

// 2.1.185
maxOutputTokensOverride: 500, agentContext: Af() }});
return wc(t.message.content) || e.slice(0, 2000)

// 2.1.220  <-- guard added here, but not to vLy
maxOutputTokensOverride: 500, agentContext: hb() }});
if (t.isApiErrorMessage) return e.slice(0, 2000);
return Jc(t.message.content) || e.slice(0, 2000)

So this call path is known to return error messages; the handling landed in one consumer and not the other. vLy's logic is otherwise byte-identical between 2.1.185 and 2.1.220.

Confirming the calls are made, not skipped

The queue is eligible sessions (user_message_count >= 2, duration_minutes >= 1) without a cached facet, capped at 50/run. Measured on two consecutive runs: 107 candidates -> 50 calls -> 0 facets; 111 candidates -> 50 calls -> 0 facets. Report 27,164 bytes, six No data panels, facets/ unchanged, nothing in --debug.

Changing only the model makes it work:

CLAUDE_CODE_DISABLE_1M_CONTEXT=1 \
ANTHROPIC_DEFAULT_OPUS_MODEL=claude-haiku-4-5-20251001 \
  claude -p "/insights" --tools "" --no-session-persistence

50 facets/run, report grows to 83,002 bytes, zero No data panels. Same 50-way concurrency succeeds on Haiku, so this isn't fan-out or rate limiting — it's specific to the Opus call. (Env: macOS 15 / darwin-arm64, Max subscription, default Opus 5 1M context. Reporter above is on Windows, so the trigger is not platform-specific.)

Suggested fix

  1. Add the isApiErrorMessage guard to vLy, matching its sibling.
  2. Log on both silent returns. Right now total failure and a genuinely empty corpus are indistinguishable to the user.
  3. If N extractions were attempted and 0 succeeded, say so rather than rendering _No insights generated_ — that phrasing reads as "you have no interesting usage" instead of "the analysis stage failed," which is why this went unnoticed for six weeks on my machine.

Separate issue in the same pipeline, worth fixing alongside

Facet generation needs the parsed transcript, which is only in memory for sessions parsed this run — and a session is parsed only when its session-meta entry is missing or stale:

if (z && (z.transcript_mtime === void 0 || z.transcript_mtime >= q.mtime)) s.push(z);  // cached, not parsed
else if (!z) { if (l < i) { a.push(...); l++ } }                                       // parsed, i = 200

The metadata cap is 200/run, the facet cap is 50/run. So every run writes metadata for 200 sessions but facets for at most 50, and the other 150 get a fresh metadata entry, are never re-parsed, and can never receive a facet no matter how many times /insights is re-run. Two aggravators: transcript_mtime === void 0 counts as fresh, so entries written before that field existed are permanently stranded (372 of mine), and a closed session's transcript never changes, so the >= branch never re-parses it either.

Suggested fix: gate parsing on the facet being missing rather than the metadata being stale, or raise the facet cap to match the metadata cap so the two caches advance together.

Workaround for anyone stuck with a partly-populated report: delete the session-meta entry for every eligible session lacking a facet, then re-run. That cleared 680 stranded sessions for me in 7 rounds at 50/round.

bradfeld · 29 days ago

Follow-up with a measurement that widens the fix scope: the same silent failure hits a second consumer — the narrative synthesis, not just per-session facet extraction.

Setup: 734 facets now cached on disk (backfilled via the Haiku workaround above). Ran /insights twice over the same corpus, changing only the model.

| | plain Opus | ANTHROPIC_DEFAULT_OPUS_MODEL=claude-haiku-4-5-20251001 |
|---|---|---|
| report size | 35,275 bytes | 80,704 bytes |
| No data panels | 0 | 0 |
| facet-derived charts | populated | populated |
| narrative <h2 id="section-*"> blocks | zero emitted | all 7 present |
| insights payload | {} | full |

The chart panels read cached facets off disk with no model call, so they populate under both. The narrative sections (What You Work On, How You Use Claude Code, Impressive Things You Did, Where Things Go Wrong, Existing CC Features to Try, New Ways to Use Claude Code, On the Horizon) require a model call, and under Opus that call fails the same silent way — {} payload, _No insights generated_, no error, no log.

So a fix limited to vLy would restore facet generation but still leave a report with populated charts and no prose. Both call sites need the isApiErrorMessage guard and the logging.

This also explains the reports in this thread that showed No data charts despite a non-empty facets/ directory: the cached facets were for sessions outside the analyzed date window, so none matched. Once enough facets covered the current window, the charts filled while the prose stayed empty — which is a useful diagnostic signal for anyone triaging this. Charts populated + prose missing means the cache is fine and the model call is the sole failure.

thomas-richard-veeva · 13 days ago

My duplicate https://github.com/anthropics/claude-code/issues/83849 was on: macOS (arm64)

So the tag platform:windows is probably inaccurate - it's likely on a common component.