gastownhall/beads · error

comment counts: %w

Error message

comment counts: %w

What it means

The comment use case's internal counts helper fetches per-issue comment counts from the repository via CountsByIssueIDs. When the underlying repository/storage query fails, the error is wrapped as "comment counts: %w" and propagated to GetCommentCounts or GetWispCommentCounts. It indicates a storage-layer failure, not a caller input problem.

Source

Thrown at internal/storage/domain/comment.go:64

}

var _ CommentUseCase = (*commentUseCaseImpl)(nil)

func (u *commentUseCaseImpl) GetCommentCounts(ctx context.Context, issueIDs []string) (map[string]int, error) {
	return u.counts(ctx, issueIDs, false)
}

func (u *commentUseCaseImpl) GetWispCommentCounts(ctx context.Context, wispIDs []string) (map[string]int, error) {
	return u.counts(ctx, wispIDs, true)
}

func (u *commentUseCaseImpl) counts(ctx context.Context, ids []string, useWisp bool) (map[string]int, error) {
	if len(ids) == 0 {
		return map[string]int{}, nil
	}
	out, err := u.commentRepo.CountsByIssueIDs(ctx, ids, CommentOpts{UseWispsTable: useWisp})
	if err != nil {
		return nil, fmt.Errorf("comment counts: %w", err)
	}
	return out, nil
}

func (u *commentUseCaseImpl) GetCommentsForIssues(ctx context.Context, issueIDs []string) (map[string][]*types.Comment, error) {
	return u.list(ctx, issueIDs, false)
}

func (u *commentUseCaseImpl) GetCommentsForIssue(ctx context.Context, issueID string) ([]*types.Comment, error) {
	return u.listOne(ctx, issueID, false)
}

func (u *commentUseCaseImpl) CountCommentsForIssue(ctx context.Context, issueID string) (int64, error) {
	return u.countOne(ctx, issueID, false)
}

func (u *commentUseCaseImpl) IterCommentsForIssue(ctx context.Context, issueID string) (storage.Iter[types.Comment], error) {
	return u.iterOne(ctx, issueID, false)

View on GitHub (pinned to 71377f2769)

Solutions

  1. Unwrap the inner error to find the storage-level cause (timeout, missing table, corruption).
  2. Check that the database is accessible and not locked by another process; retry on transient failures.
  3. If UseWispsTable mode fails, verify the wisps table exists/migrated, or retry via GetCommentCounts (non-wisp path).
  4. Check context cancellation — ensure no upstream timeout cancels ctx before the query completes.

Example fix

// before
ctx := context.Background() // or an already-canceled request ctx
counts, err := uc.GetWispCommentCounts(ctx, ids)
// after
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
counts, err := uc.GetWispCommentCounts(ctx, ids)
if err != nil {
    var retryable bool
    if errors.Is(err, context.DeadlineExceeded) { retryable = true }
    // handle or retry
}
Defensive patterns

Strategy: retry

Validate before calling

if len(ids) == 0 {
    return map[string]int{}, nil // skip the call entirely for empty input
}
counts, err := useCase.GetCommentCounts(ctx, ids)

Try / catch

counts, err := useCase.GetCommentCounts(ctx, ids)
if err != nil {
    if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, context.Canceled) {
        // retry with a fresh context
        counts, err = useCase.GetCommentCounts(context.Background(), ids)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling GetCommentCounts or GetWispCommentCounts with a non-empty ID list while the backing store fails: database closed/unavailable, corrupt rows, context canceled or timed out mid-query, or wisp-table mode used when the wisps table is missing/unreadable.

Common situations: Database file locked or corrupted; queries issued with an expired/canceled context (user aborted, request timeout); schema drift where the wisps table is absent in older databases; transient Dolt/SQLite failures.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/bac5c888a373d940. Report an issue: GitHub.