gastownhall/beads · error
no store is open for this workspace
Error message
no store is open for this workspace
What it means
This error is produced by ClassifyPublicCreateError when a create's dependency/parent/waits-for relationship names a row that does not exist in the database. The storage layer returns either a typed *domain.DependencyEndpointNotFoundError or a missing-foreign-key database error; this classifier rewrites it into a deterministic validation refusal: storage.ErrValidation wrapping the original error and storage.ErrNotFound. It exists so every backend reports a missing target uniformly instead of leaking backend-specific infrastructure errors.
Source
Thrown at cmd/bd/serve.go:695
// returns a claimer that runs the workspace's on_update script for every claim
// it lands. This server documents that hooks do not fire, so the hook layer has
// to come off; the telemetry layer beneath it must not, or every request this
// process serves goes unspanned and untimed. httpapi.Listen refuses a
// hook-firing role rather than trusting this comment, so getting it wrong is a
// startup error rather than a silent subprocess per claim.
//
// The assertion is conditional because a BD_NO_HOOKS=1 workspace has no hook
// layer to peel.
//
// It returns the WHOLE set httpapi.Config requires; Listen refuses a partial
// set (see checkDatabaseSource), so a role missing here is a startup failure
// rather than a nil dereference on the first request that reaches it.
func serveIssueRoles(src serveRoleSource, journalEnabled bool) (serveRoles, error) {
var roles serveRoles
if src == nil {
// A set of nil roles would reach Listen as "no database source" —
// true, and useless. Name the condition that actually happened.
return roles, errors.New("no store is open for this workspace")
}
if hooked, ok := src.(*storage.HookFiringStore); ok {
src = hooked.Unwrap()
}
// Each entry binds one Config field to the accessor that fills it, and
// names itself in the failure.
type binding struct {
name string
get func() error
}
for _, b := range []binding{
{"issue reader", func() (err error) { roles.reader, err = src.IssueReader(); return }},
{"issue claimer", func() (err error) { roles.claimer, err = src.IssueClaimer(); return }},
{"batch closer", func() (err error) { roles.batchCloser, err = src.BatchCloser(); return }},
{"ready claimer", func() (err error) { roles.readyClaimer, err = src.ReadyClaimer(); return }},
{"issue releaser", func() (err error) { roles.releaser, err = src.Releaser(); return }},
{"issue lifecycle", func() (err error) { roles.lifecycle, err = src.IssueLifecycle(); return }},View on GitHub (pinned to 71377f2769)
Solutions
- Verify each dependency TargetID / ParentID / WaitsFor.SpawnerID exists before creating: look the ID up with the same storage handle.
- Fix typos or wrong prefixes in the referenced IDs.
- If the target is created in the same batch, ensure ordering/commit so it exists before the referencing create executes.
- Handle errors.Is(err, storage.ErrNotFound) in the caller and surface a user-facing 'unknown issue ID' message instead of retrying.
Example fix
// before
req.Dependencies = []publicops.DependencyInput{{TargetID: "bd-999", Type: "blocks"}} // bd-999 not in DB
// after
if _, err := store.GetIssue(ctx, "bd-999"); err != nil { return fmt.Errorf("target bd-999 missing: %w", err) }
req.Dependencies = []publicops.DependencyInput{{TargetID: "bd-999", Type: "blocks"}} Defensive patterns
Strategy: validation
Validate before calling
for _, d := range req.Dependencies {
if _, err := store.GetIssue(ctx, d.TargetID); err != nil {
return fmt.Errorf("dependency target %s does not exist", d.TargetID)
}
}
if req.ParentID != "" {
if _, err := store.GetIssue(ctx, req.ParentID); err != nil { return fmt.Errorf("parent %s does not exist", req.ParentID) }
} Type guard
var missing *domain.DependencyEndpointNotFoundError
if errors.As(err, &missing) || (errors.Is(err, storage.ErrValidation) && errors.Is(err, storage.ErrNotFound)) {
// missing target
targetID := ""
if errors.As(err, &missing) { targetID = missing.EndpointID } Try / catch
if err := store.ExecuteCreate(ctx, req); err != nil {
if errors.Is(err, storage.ErrValidation) && errors.Is(err, storage.ErrNotFound) {
return fmt.Errorf("unknown dependency target: %w", err)
}
return err
} Prevention
- Look up every referenced ID with the same storage handle before creating.
- Never copy IDs across environments or databases.
- Check that referenced issues were not deleted or left ephemeral.
- Create referenced issues before the referencing one, or in a known order.
When it happens
Trigger: Calling ExecuteCreate/ExecuteCreateBatch with a Dependencies entry, ParentID, or WaitsFor.SpawnerID whose TargetID/ID matches no existing issue; the dependency write fails with a missing endpoint or foreign-key violation and ClassifyPublicCreateError rewrites it at public_create.go:115.
Common situations: Typo in a dependency target ID; referencing an issue in a different database/prefix; the target issue was deleted (or was ephemeral and never persisted) before the create ran; copying issue IDs from another environment.
Related errors
- not found
- no absolute native user directory is available
- ExternalDoltConfig: set either Socket OR (Host, Port), not b
- ExternalDoltConfig: must set Socket or (Host, Port)
- ExternalDoltConfig: Host requires Port
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/03e31303317841d9.
Report an issue: GitHub.