gastownhall/beads · warning
Failed to preview push %s in %s: %s
Error message
Failed to preview push %s in %s: %s
What it means
This is a warning emitted by the push engine's dry-run (preview) path when the tracker adapter's BatchPushDryRun returned a per-issue error entry in batchResult.Errors. The engine does not abort; it logs the failure for the specific local issue (item.LocalID) against the external tracker's display name and continues with the rest of the batch. It means one issue in your preview could not be simulated — e.g. validation or API lookup failed for that item only.
Source
Thrown at internal/tracker/engine.go:993
stats.Skipped += skipped
if len(pushIssues) == 0 {
return stats, nil
}
if opts.DryRun {
if dryRunner, ok := e.Tracker.(BatchPushDryRunner); ok {
batchResult, err := dryRunner.BatchPushDryRun(ctx, pushIssues, forceIDs)
if err != nil {
return nil, fmt.Errorf("previewing batch push: %w", err)
}
e.renderBatchDryRun(pushIssues, batchResult)
stats.Created += len(batchResult.Created)
stats.Updated += len(batchResult.Updated)
stats.Skipped += len(batchResult.Skipped)
stats.Errors += len(batchResult.Errors)
stats.Warnings = append(stats.Warnings, batchResult.Warnings...)
for _, item := range batchResult.Errors {
if item.LocalID != "" {
e.warn("Failed to preview push %s in %s: %s", item.LocalID, e.Tracker.DisplayName(), item.Message)
continue
}
e.warn("Failed to preview pushes in %s: %s", e.Tracker.DisplayName(), item.Message)
}
return stats, nil
}
} else {
batchResult, err := batchTracker.BatchPush(ctx, pushIssues, forceIDs)
if err != nil {
return nil, fmt.Errorf("batch pushing issues: %w", err)
}
e.applyBatchPushResult(ctx, batchResult)
stats.Created += len(batchResult.Created)
stats.Updated += len(batchResult.Updated)
stats.Skipped += len(batchResult.Skipped)
stats.Errors += len(batchResult.Errors)
stats.Warnings = append(stats.Warnings, batchResult.Warnings...)
for _, item := range batchResult.Errors {View on GitHub (pinned to 71377f2769)
Solutions
- Read the %s message in the warning to see which item failed; fix that issue's data (title length, state, external_ref) locally and re-run the dry-run.
- Verify the remote tracker configuration (states, labels, project/board IDs) matches what the local issues reference.
- If the external_ref is stale, clear it or use force-push IDs so the item is treated as a create instead of an update.
- Check the adapter implementation's BatchPushDryRun to confirm why it returned a per-item error instead of skipping.
Example fix
// before: stale external_ref fails preview update issue.ExternalRef = "github:does-not-exist-999" // after: reset ref so preview treats it as a create issue.ExternalRef = "" // or re-link to the correct remote issue
Defensive patterns
Strategy: validation
Validate before calling
// Before dry-run/push, sanity-check each issue that will be sent:
func validateForPush(issue *types.Issue) error {
if issue.Title == "" || len(issue.Title) > 256 {
return fmt.Errorf("issue %s: title missing or too long", issue.ID)
}
if issue.ExternalRef != "" && !tracker.IsExternalRef(issue.ExternalRef) {
return fmt.Errorf("issue %s: stale external_ref %q", issue.ID, issue.ExternalRef)
}
return nil
} Type guard
func hasBatchItemLocalID(item BatchErrorItem) bool { return item.LocalID != "" } // non-empty LocalID => per-issue diagnostics available Try / catch
stats, err := engine.Sync(ctx, opts)
if err != nil {
return fmt.Errorf("sync aborted: %w", err)
}
for _, w := range stats.Warnings { // preview item failures land here
log.Warnf("preview warning: %s", w)
}
if stats.Errors > 0 { /* inspect and fix named issues, then re-run */ } Prevention
- Keep external_ref values in sync with the remote tracker; clear refs when the remote item is deleted.
- Run the dry-run first and fix every preview warning before the real push.
- Validate titles/labels/states against the tracker's actual configuration before syncing.
- Keep tracker auth tokens fresh and scoped for write access.
When it happens
Trigger: Running a dry-run push (opts.DryRun=true) against a tracker implementing BatchPushDryRunner where BatchPushDryRun succeeds overall but returns an error item with a non-empty LocalID — e.g. the tracker API rejected that one issue during the preview (invalid state/label, missing external ref resolution, per-item validation).
Common situations: Previewing `bd sync --dry-run` against GitHub/Linear/Jira where one issue references a state or label that doesn't exist remotely, an issue's external_ref points to a deleted remote item, or a per-issue field violates the tracker's limits (title length, missing required field).
Related errors
- Failed to preview pushes in %s: %s
- Failed to push %s in %s: %s
- Failed to push issues in %s: %s
- Failed to create %s in %s: %v
- database not available: %w
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/377216deed26c331.
Report an issue: GitHub.