gastownhall/beads · error

read issue_id_mode: %w

Error message

read issue_id_mode: %w

What it means

Wraps failure of cfgRepo.GetConfig(ctx, "issue_id_mode") inside mintTopLevelID for non-wisp issues. bd needs to know whether to use counter or hash IDs; the config read itself failed (not an invalid value — an unset/"counter"/anything falls through to hash mode).

Source

Thrown at internal/storage/domain/issue.go:1604

// mintTopLevelID generates a fresh top-level ID for an issue that has no
// ExplicitID and no ParentID. Honors counter mode for non-wisps (config key
// issue_id_mode=counter); otherwise uses adaptive hash-mode IDs that mirror
// issueops.GenerateIssueIDInTable. Reads issue.CreatedAt (caller must have
// stabilized it before this call so retries hash the same value).
func (u *issueUseCaseImpl) mintTopLevelID(ctx context.Context, issue *types.Issue, actor string, useWisp bool) (string, error) {
	prefix, err := u.resolveTopLevelPrefix(ctx, issue, useWisp)
	if err != nil {
		return "", err
	}

	// Counter mode applies only to the issues table — wisps always hash-mint
	// because there is no wisp_counter table and ephemeral churn would make
	// a monotonic counter meaningless.
	if !useWisp {
		mode, err := u.cfgRepo.GetConfig(ctx, "issue_id_mode")
		if err != nil {
			return "", fmt.Errorf("read issue_id_mode: %w", err)
		}
		if mode == "counter" {
			n, err := u.issueRepo.NextCounterID(ctx, prefix)
			if err != nil {
				return "", err
			}
			return fmt.Sprintf("%s-%d", prefix, n), nil
		}
	}

	cfg, err := u.cfgRepo.GetAdaptiveIDConfig(ctx)
	if err != nil {
		return "", fmt.Errorf("read adaptive id config: %w", err)
	}
	tableOpts := IssueTableOpts{UseWispsTable: useWisp}

	count, err := u.issueRepo.CountForPrefix(ctx, prefix, tableOpts)
	if err != nil {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Check DB connectivity and retry the create.
  2. Ensure the config table exists and is initialized (bd init / bd doctor).
  3. Explicitly set the mode to silence ambiguity: bd config set issue_id_mode hash (or counter).
  4. Inspect the wrapped error for a driver-level cause and fix storage.
Defensive patterns

Strategy: retry

Validate before calling

// probe config availability before minting
if _, err := cfgRepo.GetConfig(ctx, "issue_id_mode"); err != nil {
    return fmt.Errorf("config store unreachable: %w", err)
}

Try / catch

if err != nil {
    if isTransientStorageErr(err) {
        return retryWithBackoff(func() error { return mintID(ctx, issue) })
    }
    return fmt.Errorf("issue_id_mode unreadable: %w", err)
}

Prevention

When it happens

Trigger: Minting a new top-level regular (non-wisp) issue ID while the issue_id_mode config read errors: storage down, config table missing, canceled context.

Common situations: Database outage during create; uninitialized workspace; version/schema mismatch between bd binary and DB config table.

Related errors


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