gastownhall/beads · error
failed to summarize: %w
Error message
failed to summarize: %w
What it means
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.
Source
Thrown at internal/compact/compactor.go:120
return fmt.Errorf("issue %s is not eligible for Tier 1 compaction", issueID)
}
issue, err := c.store.GetIssue(ctx, issueID)
if err != nil {
return fmt.Errorf("failed to fetch issue: %w", err)
}
// Calculate original size
originalSize := len(issue.Description) + len(issue.Design) + len(issue.Notes) + len(issue.AcceptanceCriteria)
if c.config.DryRun {
return fmt.Errorf("dry-run: would compact %s (original size: %d bytes)", issueID, originalSize)
}
// Get summary from AI
summary, err := c.summarizer.SummarizeTier1(ctx, issue)
if err != nil {
return fmt.Errorf("failed to summarize: %w", err)
}
// Check if compaction would actually reduce size
compactedSize := len(summary)
if compactedSize >= originalSize {
warningMsg := fmt.Sprintf("Tier 1 compaction skipped: summary (%d bytes) not shorter than original (%d bytes)", compactedSize, originalSize)
if err := c.store.AddComment(ctx, issueID, "compactor", warningMsg); err != nil {
return fmt.Errorf("failed to record warning: %w", err)
}
return fmt.Errorf("compaction would increase size (%d → %d bytes), keeping original", originalSize, compactedSize)
}
// Archive the original content BEFORE the destructive overwrite, so the
// compaction is reversible (bd restore reads this snapshot). If archiving
// fails we abort with the original content intact rather than lose it.
if err := c.store.SnapshotIssue(ctx, issueID, 1); err != nil {
return fmt.Errorf("failed to archive pre-compaction snapshot: %w", err)
}View on GitHub (pinned to 71377f2769)
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
Example fix
// before
if err := c.CompactTier1(ctx, id); err != nil { return err }
// after
err := c.CompactTier1(ctx, id)
if err != nil && strings.Contains(err.Error(), "failed to summarize") {
time.Sleep(backoff)
err = c.CompactTier1(ctx, id)
}
return err Defensive patterns
Strategy: retry
Validate before calling
if os.Getenv("ANTHROPIC_API_KEY") == "" { return fmt.Errorf("no API key") }
if err := ctx.Err(); err != nil { return err } Try / catch
err := c.CompactTier1(ctx, id)
if err != nil && strings.Contains(err.Error(), "failed to summarize") {
select {
case <-time.After(exponentialBackoff(attempt)):
err = c.CompactTier1(ctx, id)
case <-ctx.Done():
return ctx.Err()
}
}
return err Prevention
- 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
When it happens
Trigger: 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.
Common situations: Expired or revoked Anthropic API key; quota exhaustion during large batch compactions; transient network outage; context deadline too short for large issues; API downtime.
Related errors
- failed to remove backup: %w
- Notion create database response did not include a child data
- ensureProxiedServerConfig: pick free port: %w
- pull: %w
- push: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/2c9bd73c1d21f55d.
Report an issue: GitHub.