gastownhall/beads · error · storage.ErrPrefixMismatch

%w: issue ID %s does not match configured prefix %s

Error message

%w: issue ID %s does not match configured prefix %s

What it means

ValidateIssueIDPrefix enforces that an explicitly supplied issue ID starts with the configured prefix (e.g. "bd-") for the repository, wrapping storage.ErrPrefixMismatch. This prevents cross-repo ID confusion: beads repos are expected to own a distinct prefix so IDs from different databases never collide. The error lists the offending ID and the configured prefix.

Source

Thrown at internal/storage/issueops/create.go:580

	}
	return nil
}

// ValidateIssueIDPrefix validates that the issue ID matches the configured prefix
// or any of the allowed_prefixes.
func ValidateIssueIDPrefix(id, prefix, allowedPrefixes string) error {
	if strings.HasPrefix(id, prefix+"-") {
		return nil
	}
	if allowedPrefixes != "" {
		for _, allowed := range strings.Split(allowedPrefixes, ",") {
			allowed = strings.TrimSpace(allowed)
			if allowed != "" && strings.HasPrefix(id, allowed+"-") {
				return nil
			}
		}
	}
	return fmt.Errorf("%w: issue ID %s does not match configured prefix %s", storage.ErrPrefixMismatch, id, prefix)
}

// ParseHierarchicalID checks if an ID is hierarchical (e.g., "bd-abc.1")
// and returns the parent ID and child number.
func ParseHierarchicalID(id string) (parentID string, childNum int, ok bool) {
	lastDot := strings.LastIndex(id, ".")
	if lastDot == -1 {
		return "", 0, false
	}
	parentID = id[:lastDot]
	var num int
	if _, err := fmt.Sscanf(id[lastDot+1:], "%d", &num); err != nil {
		return "", 0, false
	}
	return parentID, num, true
}

// AllWisps returns true if every issue in the slice should be routed to the

View on GitHub (pinned to 71377f2769)

Solutions

  1. Remap the issue ID to use the current repo's prefix (e.g. "bd-<hash>") before creating it.
  2. Update the configured allowed prefixes (.beads/config or equivalent) to include the prefix of the ID you are inserting.
  3. Let beads assign the ID (omit the explicit ID) instead of supplying a foreign-prefixed one.
  4. If you intentionally need a foreign ID, use the documented force/override option if available; otherwise keep the data in its own prefixed repo.

Example fix

// before
issue.ID = "gt-abc123" // repo prefix is "bd"
err := issueops.PreparePublicCreateRequest(...) // ErrPrefixMismatch
// after
issue.ID = "bd-abc123" // matches configured prefix, or leave ID empty to auto-assign
err := issueops.PreparePublicCreateRequest(...)
Defensive patterns

Strategy: validation

Validate before calling

prefix := cfg.IssuePrefix // e.g. "bd"
if issue.ID != "" && !strings.HasPrefix(issue.ID, prefix+"-") {
    issue.ID = prefix + "-" + strings.TrimPrefix(issue.ID, prefix+"-")
}

Type guard

func hasValidPrefix(id, prefix string) bool {
    return id == "" || strings.HasPrefix(id, strings.TrimSpace(prefix)+"-")
}

Try / catch

if err := createIssue(issue); err != nil {
    if errors.Is(err, storage.ErrPrefixMismatch) {
        issue.ID = remapPrefix(issue.ID, cfg.IssuePrefix)
        return createIssue(issue)
    }
    return err
}

Prevention

When it happens

Trigger: Creating an issue with an explicit ID whose prefix is not in the allowed-prefix configuration (e.g. inserting an issue with ID "gt-abc" into a repo configured with prefix "bd"), via assignCreateIssueIDInTx or PreparePublicCreateRequest with a caller-supplied ID.

Common situations: Importing JSONL from a different beads repo without remapping prefixes; hardcoding IDs with the wrong prefix in scripts; renaming a repo's prefix but reusing old IDs; cross-replica sync tooling that copies IDs verbatim between differently-prefixed repos.

Related errors


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