gastownhall/beads · error

import memory %q: %w

Error message

import memory %q: %w

What it means

While landing the import batch inside the unit of work, each memory record is written via the config use case (SetConfig). If that write fails, the error is wrapped with the offending memory key as "import memory %q". The whole batch transaction then aborts and rolls back, so nothing from the batch is committed.

Source

Thrown at internal/storage/uow/importer.go:95

					})
				},
				OnStaleRejected: func(issueID string) {
					if _, ok := staleRejected[issueID]; ok {
						return
					}
					staleRejected[issueID] = struct{}{}
					result.StaleRejectedIDs = append(result.StaleRejectedIDs, issueID)
				},
			}
			if _, err := storageissueops.CreateIssuesInTxWithResult(ctx, runner, request.Issues, request.Actor, opts); err != nil {
				return publicops.ImportBatchResult{}, "", err
			}
			result.Created = len(request.Issues) - len(staleRejected)
		}

		for _, memory := range request.Memories {
			if err := uw.ConfigUseCase().SetConfig(ctx, memory.Key, memory.Value); err != nil {
				return publicops.ImportBatchResult{}, "", fmt.Errorf("import memory %q: %w", memory.Key, err)
			}
			result.MemoriesImported++
		}

		// config.yaml is authoritative for issue_prefix on the import flow
		// (be-llaf); a read or write failure here degrades to "not synced"
		// rather than failing the batch, matching the classic path.
		if request.SyncIssuePrefix != "" {
			stored, _ := uw.ConfigUseCase().GetConfig(ctx, "issue_prefix")
			if stored != request.SyncIssuePrefix {
				if err := uw.ConfigUseCase().SetConfig(ctx, "issue_prefix", request.SyncIssuePrefix); err == nil {
					result.PrefixSynced = true
				}
			}
		}

		return result, importBatchCommitMessage(request, result), nil
	})

View on GitHub (pinned to 71377f2769)

Solutions

  1. Sanitize memory entries before import: skip or fix entries with empty/invalid keys.
  2. Retry the import after confirming DB connectivity if the wrapped error is a connection/serialization failure (RunTxResult already retries serialization, but hard I/O errors are not retried).
  3. Inspect the wrapped inner error for the root cause — it names the exact SetConfig failure.
  4. Update the failing key's value or drop the record from the import source, then re-run; the batch is atomic so no partial state needs cleanup.

Example fix

// before
for _, m := range rawMemories {
	request.Memories = append(request.Memories, publicops.MemoryEntry{Key: m.Key, Value: m.Value}) // m.Key may be ""
}
// after
for _, m := range rawMemories {
	if m.Key == "" {
		log.Printf("skipping memory with empty key")
		continue
	}
	request.Memories = append(request.Memories, publicops.MemoryEntry{Key: m.Key, Value: m.Value})
}
Defensive patterns

Strategy: try-catch

Validate before calling

for i, m := range request.Memories {
	if strings.TrimSpace(m.Key) == "" {
		return fmt.Errorf("memory entry %d has empty key", i)
	}
}

Type guard

func validMemories(ms []publicops.MemoryEntry) bool {
	for _, m := range ms {
		if m.Key == "" {
			return false
		}
	}
	return true
}

Try / catch

result, err := imp.ImportBatch(ctx, req)
if err != nil {
	var key string
	if n, serr := fmt.Sscanf(err.Error(), "import memory %q:", &key); serr == nil && n == 1 {
		return fmt.Errorf("import aborted at memory %q (batch rolled back): %w", key, err)
	}
	return err
}

Prevention

When it happens

Trigger: Calling ImportBatch with request.Memories whose Key cannot be written by uw.ConfigUseCase().SetConfig — e.g. an empty or invalid key, a key colliding with protected config, storage-layer failures (connection dropped mid-tx), or a duplicate write conflict inside the transaction.

Common situations: Import files (JSONL) containing malformed memory entries with empty keys or control characters; concurrent `bd` processes writing the same config key during sync; database connectivity loss partway through a large import.

Related errors


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