gastownhall/beads · critical
batch create failed and recovery search also failed: %w (bat
Error message
batch create failed and recovery search also failed: %w (batch error: %v)
What it means
During BatchCreateIssues, the issueBatchCreate HTTP request failed (err from c.Execute) AND the idempotency recovery search (recoverAfterAmbiguousBatch, which looks for the bd-idempotency marker in descriptions) also failed. Because Linear may have partially applied the batch, the client cannot tell which issues exist, so it returns all issues confirmed so far (allIssues) plus this combined error wrapping both the recovery error and the original batch error.
Source
Thrown at internal/linear/client.go:1080
if end > len(inputs) {
end = len(inputs)
}
chunk := inputs[start:end]
req := &GraphQLRequest{
Query: query,
Variables: map[string]interface{}{
"input": map[string]interface{}{
"issues": chunk,
},
},
}
data, err := c.Execute(ctx, req)
if err != nil {
found, recoverErr := c.recoverAfterAmbiguousBatch(ctx, chunk)
if recoverErr != nil {
return allIssues, fmt.Errorf("batch create failed and recovery search also failed: %w (batch error: %v)", recoverErr, err)
}
allIssues = append(allIssues, found...)
if len(found) < len(chunk) {
return allIssues, fmt.Errorf("batch create failed; %d of %d issues unconfirmed (batch error: %v)", len(chunk)-len(found), len(chunk), err)
}
continue
}
var batchResp IssueBatchCreateResponse
if err := json.Unmarshal(data, &batchResp); err != nil {
return allIssues, fmt.Errorf("failed to parse batch create response: %w", err)
}
if !batchResp.IssueBatchCreate.Success {
found, recoverErr := c.recoverAfterAmbiguousBatch(ctx, chunk)
if recoverErr != nil {
return allIssues, fmt.Errorf("batch create unsuccessful and recovery search also failed: %w", recoverErr)
}View on GitHub (pinned to 71377f2769)
Solutions
- Inspect the wrapped recovery error (%w) first — it is the primary cause; the batch error is appended as context.
- Wait for rate limits to reset, then re-run recovery/idempotent batch creation; issues from earlier chunks already returned are safe.
- Search Linear manually for the idempotency markers of the affected chunk to reconcile duplicates.
- Verify API token validity and network reachability to api.linear.app.
Example fix
// before
issues, err := client.BatchCreateIssues(ctx, inputs)
if err != nil {
return err // duplicates possible if blindly retried
}
// after
issues, err := client.BatchCreateIssues(ctx, inputs)
if err != nil {
if strings.Contains(err.Error(), "recovery search also failed") {
// do NOT re-create blindly; reconcile via marker search first
return fmt.Errorf("ambiguous batch outcome, reconcile before retry: %w", err)
}
return err
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-check connectivity and auth before batch creation
if err := client.CheckAuth(ctx); err != nil {
return fmt.Errorf("linear unreachable/unauthorized, aborting batch: %w", err)
}
// Ensure every input carries the idempotency marker
for _, in := range inputs {
if !strings.Contains(in.Description, "<!-- bd-idempotency:") {
return errors.New("all batch inputs must embed the bd-idempotency marker")
}
} Type guard
func isAmbiguousBatchFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "recovery search also failed")
} Try / catch
issues, err := client.BatchCreateIssues(ctx, inputs)
if isAmbiguousBatchFailure(err) {
// Do NOT blindly re-create; wait/backoff, then re-run with the SAME markers
<-time.After(backoff)
issues, err = client.BatchCreateIssues(ctx, inputs)
} Prevention
- Embed the bd-idempotency marker in every issue description before batching.
- Apply exponential backoff on Linear rate-limit (429) responses.
- Treat already-returned issues from earlier chunks as created; never re-include them.
- Monitor Linear status/auth so combined mutation+search failures are detected early.
When it happens
Trigger: Calling Client.BatchCreateIssues when the Execute call fails (network error, timeout, GraphQL error) and the subsequent per-issue FindIssueByDescriptionContains search inside recoverAfterAmbiguousBatch also errors (e.g. the search API is also unreachable or rate-limited).
Common situations: Linear outage or rate limiting affecting both mutation and search endpoints; expired API token causing both calls to fail; inputs whose descriptions lack the idempotency marker combined with a search failure.
Related errors
- batch create failed; %d of %d issues unconfirmed (batch erro
- failed to parse batch create response: %w
- failed to parse update response: %w
- failed to fetch issue by identifier: %w
- failed to fetch teams: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/baf89f4f30f42407.
Report an issue: GitHub.