gastownhall/beads · error · issueops.ErrValidation
%w: bootstrap requires a project id; this role does not mint
Error message
%w: bootstrap requires a project id; this role does not mint one
What it means
ValidateBootstrapRequest wraps issueops.ErrValidation when ProjectID is empty. The bootstrap role expects the project (or equivalent substrate identifier) to already exist and be supplied by the caller; it does not mint one itself. Like the prefix check, this fires before any transaction opens.
Source
Thrown at internal/workapi/bootstrap.go:56
// VerifyIdentity answers with are one value on every backend, including the
// unit-of-work one whose write does not pass through that plane's normalizer.
func NormalizeBootstrapPrefix(prefix string) string {
return strings.TrimRight(prefix, "-")
}
// ValidateBootstrapRequest refuses a bootstrap that cannot produce a usable
// workspace and returns the request as it will be WRITTEN.
//
// Every implementation validates through it BEFORE opening a transaction, which
// is what makes issueops.Bootstrapper's "a refusal writes nothing" true of the
// connection as well as of the keys.
func ValidateBootstrapRequest(req issueops.BootstrapRequest) (issueops.BootstrapRequest, error) {
req.Prefix = NormalizeBootstrapPrefix(req.Prefix)
if req.Prefix == "" {
return issueops.BootstrapRequest{}, fmt.Errorf("%w: bootstrap requires a non-empty issue prefix", issueops.ErrValidation)
}
if req.ProjectID == "" {
return issueops.BootstrapRequest{}, fmt.Errorf("%w: bootstrap requires a project id; this role does not mint one", issueops.ErrValidation)
}
return req, nil
}
// RefuseIdentifiedSubstrate turns the pair a bootstrap read into the refusal
// issueops.Bootstrapper promises, or nil when the substrate is free.
//
// EITHER MARKER IS ENOUGH. A substrate several rigs share carries a prefix one
// of them chose, and a bootstrap that overwrote it would rename every id the
// others are about to mint; a substrate carrying only a project id is either a
// server-provisioned one bd must adopt rather than stamp, or a bootstrap that
// failed partway, and bd cannot tell those apart. The error carries both values
// so its caller can.
func RefuseIdentifiedSubstrate(prefix, projectID string) error {
if prefix == "" && projectID == "" {
return nil
}
return &issueops.AlreadyIdentifiedError{Prefix: prefix, ProjectID: projectID}View on GitHub (pinned to 71377f2769)
Solutions
- Create or look up the project first, then pass its id in BootstrapRequest.ProjectID
- Verify the config/env wiring actually populates ProjectID before calling bootstrap
- If you expected the library to create the project, note this role intentionally refuses to mint one — do that step in your setup code
Example fix
// before
req := issueops.BootstrapRequest{Prefix: "bd"} // ProjectID missing
// after
projectID := ensureProjectExists(ctx, client)
req := issueops.BootstrapRequest{Prefix: "bd", ProjectID: projectID} Defensive patterns
Strategy: validation
Validate before calling
if req.ProjectID == "" {
return fmt.Errorf("project must be created/selected before bootstrap")
} Try / catch
req, err := workapi.ValidateBootstrapRequest(req)
if errors.Is(err, issueops.ErrValidation) && strings.Contains(err.Error(), "project id") {
projectID, lookupErr := ensureProject(ctx)
if lookupErr != nil { return lookupErr }
return retryWithProjectID(projectID)
} Prevention
- Create the project/substrate as an explicit setup step before bootstrap
- Store and reuse the project id in config after first creation
- Never assume bootstrap mints project ids — this role refuses to
When it happens
Trigger: Calling an issueops Bootstrapper with BootstrapRequest{ProjectID: ""}; the ProjectID field was never populated from config or a prior substrate-creation step.
Common situations: Forgetting to create/fetch the project before bootstrapping; passing a struct literal with only Prefix set; config wiring that skips the project id key.
Related errors
- %w: bootstrap requires a non-empty issue prefix
- invalid database name %q (use cfg.GetDoltDatabase() to resol
- invalid group '%s'. Valid values: status, priority, type, as
- %w: delete requires at least one issue id
- %w: delete id at position %d is blank
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/7357cf84106eb82a.
Report an issue: GitHub.