{"record":{"id":"2c9bd73c1d21f55d","repo":"gastownhall/beads","slug":"failed-to-summarize-w","errorCode":null,"errorMessage":"failed to summarize: %w","messagePattern":"failed to summarize: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/compact/compactor.go","lineNumber":120,"sourceCode":"\t\treturn fmt.Errorf(\"issue %s is not eligible for Tier 1 compaction\", issueID)\n\t}\n\n\tissue, err := c.store.GetIssue(ctx, issueID)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to fetch issue: %w\", err)\n\t}\n\n\t// Calculate original size\n\toriginalSize := len(issue.Description) + len(issue.Design) + len(issue.Notes) + len(issue.AcceptanceCriteria)\n\n\tif c.config.DryRun {\n\t\treturn fmt.Errorf(\"dry-run: would compact %s (original size: %d bytes)\", issueID, originalSize)\n\t}\n\n\t// Get summary from AI\n\tsummary, err := c.summarizer.SummarizeTier1(ctx, issue)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to summarize: %w\", err)\n\t}\n\n\t// Check if compaction would actually reduce size\n\tcompactedSize := len(summary)\n\tif compactedSize >= originalSize {\n\t\twarningMsg := fmt.Sprintf(\"Tier 1 compaction skipped: summary (%d bytes) not shorter than original (%d bytes)\", compactedSize, originalSize)\n\t\tif err := c.store.AddComment(ctx, issueID, \"compactor\", warningMsg); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to record warning: %w\", err)\n\t\t}\n\t\treturn fmt.Errorf(\"compaction would increase size (%d → %d bytes), keeping original\", originalSize, compactedSize)\n\t}\n\n\t// Archive the original content BEFORE the destructive overwrite, so the\n\t// compaction is reversible (bd restore reads this snapshot). If archiving\n\t// fails we abort with the original content intact rather than lose it.\n\tif err := c.store.SnapshotIssue(ctx, issueID, 1); err != nil {\n\t\treturn fmt.Errorf(\"failed to archive pre-compaction snapshot: %w\", err)\n\t}","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/compact/compactor.go#L102-L138","documentation":"CompactTier1 calls the summarizer's SummarizeTier1 to produce the AI summary. Any failure inside the summarization call (Haiku API error, network failure, rate limit, bad response) is aborted and wrapped with this message. The issue's content is untouched at this point.","triggerScenarios":"c.summarizer.SummarizeTier1(ctx, issue) returns a non-nil error — e.g. Anthropic API rejected the key (401), rate limit hit (429), request timeout/context cancelled, network unreachable, or the model returned an unusable response.","commonSituations":"Expired or revoked Anthropic API key; quota exhaustion during large batch compactions; transient network outage; context deadline too short for large issues; API downtime.","solutions":["Inspect the wrapped error for the specific API/network failure","Verify ANTHROPIC_API_KEY validity and remaining quota","Retry with backoff — API failures are often transient","Check context timeouts are generous enough for large issues; consider pausing batch runs on repeated 429s"],"exampleFix":"// before\nif err := c.CompactTier1(ctx, id); err != nil { return err }\n// after\nerr := c.CompactTier1(ctx, id)\nif err != nil && strings.Contains(err.Error(), \"failed to summarize\") {\n    time.Sleep(backoff)\n    err = c.CompactTier1(ctx, id)\n}\nreturn err","handlingStrategy":"retry","validationCode":"if os.Getenv(\"ANTHROPIC_API_KEY\") == \"\" { return fmt.Errorf(\"no API key\") }\nif err := ctx.Err(); err != nil { return err }","typeGuard":null,"tryCatchPattern":"err := c.CompactTier1(ctx, id)\nif err != nil && strings.Contains(err.Error(), \"failed to summarize\") {\n    select {\n    case <-time.After(exponentialBackoff(attempt)):\n        err = c.CompactTier1(ctx, id)\n    case <-ctx.Done():\n        return ctx.Err()\n    }\n}\nreturn err","preventionTips":["Verify API key validity and quota before large batch runs","Use bounded retries with exponential backoff for 429/5xx from the AI API","Give the context enough deadline for large issues; pass per-call timeouts","Throttle batch concurrency to avoid rate limits"],"tags":["go","ai","network","api","retryable"],"backgroundTag":"llm-api-call-failed","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}