gastownhall/beads · error

import failed: %w

Error message

import failed: %w

What it means

The main batch write of a proxied-server import failed inside the single unit of work that commits issue rows, memories, and prefix sync. Because the proxied path uses ONE commit per invocation, a failure here means the entire import rolled back atomically — no partial rows are left behind. The wrapped cause carries the underlying storage error.

Source

Thrown at cmd/bd/import_proxied_server.go:145

	if err != nil {
		return err
	}

	// THE BATCH: rows, memories and the issue_prefix reconciliation in one
	// transaction, one history entry. The prefix sync runs even when the
	// batch is otherwise empty, exactly as the classic path's post-commit
	// sync does (be-llaf; config.yaml is authoritative, not a rename).
	batch, err := importer.ImportBatch(ctx, publicops.ImportBatchRequest{
		Actor:                getActorWithGit(),
		Issues:               issues,
		Memories:             memoryEntries,
		AllowStale:           importAllowStale,
		SkipPrefixValidation: true,
		SyncIssuePrefix:      config.GetString("issue-prefix"),
		Source:               filepath.Base(source),
	})
	if err != nil {
		return fmt.Errorf("import failed: %w", err)
	}
	result.Memories = batch.MemoriesImported

	if len(issues) > 0 {
		staleRejectedSet := make(map[string]struct{}, len(batch.StaleRejectedIDs))
		for _, id := range batch.StaleRejectedIDs {
			staleRejectedSet[id] = struct{}{}
		}
		skippedDependencies := make([]string, 0, len(batch.SkippedDependencies))
		for _, dep := range batch.SkippedDependencies {
			skippedDependencies = append(skippedDependencies, fmt.Sprintf("%s -> %s: %s", dep.IssueID, dep.DependsOnID, dep.Reason))
		}
		applyImportOutcome(&result, assembleImportResult(issues, staleSkippedIDs, changePlan, staleRejectedSet, skippedDependencies))
	} else {
		result.Skipped += len(staleSkippedIDs)
		result.StaleSkippedIDs = append(result.StaleSkippedIDs, staleSkippedIDs...)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Read the wrapped cause to identify the concrete storage failure.
  2. If the cause is stale-row rejection, re-export a fresh JSONL or pass the flag that allows stale imports (--allow-stale).
  3. Verify connectivity to the proxied server and retry — since the import is atomic, simply re-running is safe.
  4. Check database permissions/locks if the cause indicates write denial or lock timeouts.
  5. Validate the issue-prefix configuration matches the incoming records' prefixes.

Example fix

// before
bd import issues.jsonl   # import failed: stale upsert rejected: bd-123
// after
bd import --allow-stale issues.jsonl   # or re-export fresh data and retry
Defensive patterns

Strategy: retry

Validate before calling

// validate prefixes and staleness expectations before importing
for _, iss := range issues {
    if prefix := strings.SplitN(iss.ID, "-", 2)[0]; prefix != expectedPrefix {
        return fmt.Errorf("record %s has mismatched prefix %s", iss.ID, prefix)
    }
}

Try / catch

err := runImportRecordsProxied(ctx, issues, memories, source)
if err != nil {
    // proxied import is one atomic commit: safe to retry verbatim
    if isTransient(err) {
        return retry(3, backoff, func() error {
            return runImportRecordsProxied(ctx, issues, memories, source)
        })
    }
    return err
}

Prevention

When it happens

Trigger: `bd import` via proxied server where the Importer's batch CreateIssuesWithFullOptions call returns an error: stale upserts rejected by RejectStaleUpserts (when staleness is not allowed), connectivity loss, constraint conflicts, or quota/permission failures.

Common situations: Remote Dolt server connection dropped mid-import; importing rows that are stale relative to local updates (with stale imports disallowed); schema/prefix validation issues; storage lock contention on a busy shared database.

Related errors


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