gastownhall/beads · error
authorize assignee transfer %s: read claim pools: %w
Error message
authorize assignee transfer %s: read claim pools: %w
What it means
authorizeAssigneeTransfer checks whether an update changes the assignee in a way the claim-pool policy forbids. If the initial check (with nil pools) fails, it reads the 'claim.pools' config; failing to read that config produces this wrapped error. It is an infrastructure failure reading configuration, not a policy denial — a denial surfaces as the original AuthorizeAssigneeTransferWithPools error instead.
Source
Thrown at internal/storage/uow/issue_operations.go:285
return true
}
// authorizeAssigneeTransfer applies the shared assignee-transfer fence to an
// update running in this unit of work. It is the sibling of the
// issueops.AuthorizeAssigneeTransfer call in ExecuteUpdate — the same predicate
// and the same refusal — reached through the config use case because a unit of
// work has no transaction handle to read claim.pools from. The read only
// happens once the transfer is otherwise fenced, and its failure propagates
// rather than being read as "no pools configured": treating an unreadable
// config as an empty alias set would refuse pool work the fence was never meant
// to touch.
func authorizeAssigneeTransfer(ctx context.Context, uw UnitOfWork, before *types.Issue, request publicops.UpdateRequest) error {
if err := storageissueops.AuthorizeAssigneeTransferWithPools(before, request, nil); err == nil {
return nil
}
raw, err := uw.ConfigUseCase().GetConfig(ctx, "claim.pools")
if err != nil {
return fmt.Errorf("authorize assignee transfer %s: read claim pools: %w", request.IssueID, err)
}
return storageissueops.AuthorizeAssigneeTransferWithPools(before, request, storageissueops.ParseClaimPools(raw))
}
func updateSpec(request publicops.UpdateRequest) (domain.UpdateSpec, error) {
fields := make(map[string]any)
patch := request.Patch
if err := validateMetadataPatch(patch.Metadata); err != nil {
return domain.UpdateSpec{}, validationError(err)
}
setField(fields, "title", patch.Title)
setField(fields, "description", patch.Description)
setField(fields, "design", patch.Design)
setField(fields, "acceptance_criteria", patch.AcceptanceCriteria)
setField(fields, "spec_id", patch.SpecID)
setField(fields, "await_id", patch.AwaitID)
setField(fields, "status", patch.Status)
setField(fields, "priority", patch.Priority)View on GitHub (pinned to 71377f2769)
Solutions
- Read the wrapped error to see why the claim.pools config read failed.
- Initialize/repair the config store so 'claim.pools' is readable (e.g. bd doctor / migrations).
- Retry the update if the failure was transient (connection blip).
Defensive patterns
Strategy: fallback
Validate before calling
// ensure claim.pools config exists before assignee-changing updates
if _, err := cfg.GetConfig(ctx, "claim.pools"); err != nil { /* initialize config */ } Try / catch
if err != nil && strings.Contains(err.Error(), "read claim pools") {
// config infra failure: retry or repair config store
return repairAndRetry()
} Prevention
- Initialize the config store (claim.pools) during setup.
- Distinguish config-read failures from policy denials in error handling.
- Run bd doctor after fresh installs to verify config readability.
When it happens
Trigger: runUpdate hits an assignee change requiring pool authorization, and uw.ConfigUseCase().GetConfig(ctx, "claim.pools") errors (missing config store, query failure, connectivity).
Common situations: Config table absent after a fresh/failed initialization; DB unreachable during update; a UoW assembled without a ConfigUseCase (nil dereference path before the read).
Related errors
- server: NewDoltServer: doltBinExec is required
- server: NewDoltServer: rootDir is required
- server: NewDoltServer: configPath is required
- ErrAssigneeMismatch
- ErrNotOwner
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/f95508ba8c1a58d9.
Report an issue: GitHub.