gastownhall/beads · warning

Failed to push %s in %s: %s

Error message

Failed to push %s in %s: %s

What it means

Warning logged during a real (non-dry-run) batch push when the tracker's BatchPush call succeeds at the transport level but reports a per-issue error with a non-empty LocalID. The engine counts the item in stats.Errors, logs which local issue failed to push to which tracker, and continues processing. The overall sync still returns success; failed items are reported as warnings, not a fatal error.

Source

Thrown at internal/tracker/engine.go:1013

					}
					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 {
				if item.LocalID != "" {
					e.warn("Failed to push %s in %s: %s", item.LocalID, e.Tracker.DisplayName(), item.Message)
					continue
				}
				e.warn("Failed to push issues in %s: %s", e.Tracker.DisplayName(), item.Message)
			}
			return stats, nil
		}
	}

	for _, issue := range issues {
		// Limit to parent and its descendants if requested.
		if descendantSet != nil && !descendantSet[issue.ID] {
			stats.Skipped++
			continue
		}
		// Skip filtered types/states/ephemeral
		if !e.shouldPushIssue(issue, opts) {
			stats.Skipped++
			continue

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the named issue locally per the message (repair external_ref, create the missing label/state, adjust the field that failed validation) and re-run push.
  2. If the remote item no longer exists, clear issue.ExternalRef so the next push recreates it.
  3. Grant the token/app write permissions on the target repository or project if the message indicates forbidden/403.
  4. Re-run the push after transient (rate limit, 5xx) causes — stats.Errors tells you how many items need attention.

Example fix

// before: update against deleted remote item fails
"external_ref": "github:42" // deleted upstream
// after
bd update BD-42 --external-ref=""  # next push recreates the remote issue
Defensive patterns

Strategy: retry

Validate before calling

// Validate each candidate issue before push:
for _, it := range pushIssues {
    if it.ExternalRef != "" && !tracker.IsExternalRef(it.ExternalRef) {
        return fmt.Errorf("%s: external_ref %q is not a valid remote link", it.ID, it.ExternalRef)
    }
}

Type guard

func isPerItemFailure(item BatchErrorItem) bool { return item.LocalID != "" } // true => retry just that issue after fixing data

Try / catch

stats, err := engine.Sync(ctx, opts)
if err != nil {
    return err // whole-batch/transport failure
}
if stats.Errors > 0 {
    // stats.Warnings name the failing LocalIDs; repair data, then re-run.
    // Re-push is safe: unchanged items skip via stored push hashes.
    stats, err = engine.Sync(ctx, opts)
}

Prevention

When it happens

Trigger: Calling Sync/doPush against a BatchPushTracker where BatchPush returns error items carrying LocalID — e.g. remote update rejected (stale external_ref, 422 validation), remote item deleted or moved, permission denied on that specific issue, or per-item rate limit.

Common situations: A GitHub issue was closed/deleted remotely so the update 404s; labels or milestones referenced locally don't exist; the token lacks write access to the target repo; duplicate title detection rejecting a create.

Related errors


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