gastownhall/beads · error
iter comments %s: %w
Error message
iter comments %s: %w
What it means
This error is returned by collectComments in internal/workapi/detail.go when the initial call to DetailSource.IterComments fails, i.e. the comments iterator could not even be created for the issue id. It is raised before any rows are read, and BuildIssueDetails propagates it when DetailOptions.IncludeComments is true. Unlike the best-effort label/count fields, the opt-in comment stream is deliberately fail-hard: the caller asked for rows and gets a truthful error rather than a silently short list.
Source
Thrown at internal/workapi/detail.go:224
var out []*types.IssueWithDependencyMetadata
for iter.Next(ctx) {
item := iter.Value()
if item == nil {
continue
}
out = append(out, shallowDep(item))
}
if err := iter.Err(); err != nil {
return nil, fmt.Errorf("iter dependents %s: %w", id, err)
}
return out, nil
}
func collectComments(ctx context.Context, src DetailSource, id string, isWisp bool) ([]*types.Comment, error) {
iter, err := src.IterComments(ctx, id, isWisp)
if err != nil {
return nil, fmt.Errorf("iter comments %s: %w", id, err)
}
defer iter.Close() //nolint:errcheck // read-only iterator
var out []*types.Comment
for iter.Next(ctx) {
item := iter.Value()
if item == nil {
continue
}
// storage.Iter may reuse the pointer across Next calls, so a value
// we keep has to be our own copy.
comment := *item
out = append(out, &comment)
}
if err := iter.Err(); err != nil {
return nil, fmt.Errorf("iter comments %s: %w", id, err)
}
return out, nilView on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped cause with errors.Is/errors.As to identify the underlying storage error
- Verify the database is reachable and the comments (and wisps) tables exist (e.g. `bd doctor`)
- Reconnect/reopen the store and retry
- Check that the isWisp routing matches how the issue was resolved (GetIssueOrWisp)
Example fix
// before
issue, isWisp, err := workapi.GetIssueOrWisp(ctx, src, id)
// ...use issue.ID and a hardcoded isWisp=false for a second detail call
details, err := workapi.BuildIssueDetails(ctx, src, issue, isWisp, opts)
// after
issue, isWisp, err := workapi.GetIssueOrWisp(ctx, src, id)
if err != nil {
return err
}
// pass the resolved isWisp so comment queries route to the right table
details, err := workapi.BuildIssueDetails(ctx, src, issue, isWisp, opts)
if err != nil {
return fmt.Errorf("comments for %s: %w", id, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
if issue == nil || issue.ID == "" {
return fmt.Errorf("cannot load comments: no issue id")
}
if err := ctx.Err(); err != nil {
return fmt.Errorf("context already done: %w", err)
} Type guard
func isIterOpenError(err error) bool {
return err != nil && strings.HasPrefix(err.Error(), "iter comments ")
} Try / catch
details, err := workapi.BuildIssueDetails(ctx, src, issue, isWisp, workapi.DetailOptions{IncludeComments: true})
if err != nil {
if errors.Is(err, storage.ErrNotFound) {
return fmt.Errorf("issue %s vanished between resolve and comment load", issue.ID)
}
return fmt.Errorf("comment stream could not start for %s: %w", issue.ID, err)
} Prevention
- Resolve the issue with GetIssueOrWisp and pass back the returned isWisp so comment queries route to the correct table
- Set IncludeComments=true only when the caller actually consumes the rows; otherwise rely on CommentCount and CommentsOmitted
- Verify database reachability before batch detail operations
- Handle storage.ErrNotFound distinctly from infrastructure failures
When it happens
Trigger: Calling BuildIssueDetails with IncludeComments=true where src.IterComments(ctx, id, isWisp) returns a non-nil error on creation: the underlying comment table cannot be queried (database connection failure, table missing/corrupt, query preparation failure, invalid id routing between issue and wisp tables).
Common situations: Running `bd show` (or the HTTP detail handler) on an issue with comments while the Dolt database is unreachable or locked; a storage migration or version mismatch leaving the comments/wisps tables unavailable; a bug in the seam implementation misrouting a wisp id so the query targets a missing table.
Related errors
- get molecule children: %w
- failed to get issue %s: %w
- failed to remove relates-to %s -> %s: %w
- failed to get epic: %v
- failed to get issue: %v
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/8555c9d426678d74.
Report an issue: GitHub.