gastownhall/beads · error
cannot modify pinned issue %s (use --force to override)
Error message
cannot modify pinned issue %s (use --force to override)
What it means
NotPinned(force) blocks modification of pinned issues. An issue is pinned if its Pinned flag is true or its Status is StatusPinned; pins signal 'do not touch' (e.g. seed issues, anchors).
Source
Thrown at internal/validation/issue.go:68
}
// NotPinned validates that an issue is not pinned, by either of the two ways
// bd expresses a pin: the Pinned boolean column or the pinned status. Returns
// an error if either trigger fires, unless force is true.
//
// Both triggers are load-bearing because consumers disagree on which one they
// write and read (ga-z3vht). Gas Town pins by status — it enumerates pins with
// List(ListOptions{Status: StatusPinned}) across 21 sites (hook_check.go,
// prime_output.go, molecule_step.go, up.go) — while Gas City reads the boolean
// (compute_awake_set.go). Checking only one strips the other consumer's
// protection outright, so do not "simplify" either clause away.
func NotPinned(force bool) IssueValidator {
return func(id string, issue *types.Issue) error {
if issue == nil {
return nil // Let Exists() handle nil check if needed
}
if !force && (issue.Pinned || issue.Status == types.StatusPinned) {
return fmt.Errorf("cannot modify pinned issue %s (use --force to override)", id)
}
return nil
}
}
// CanonicalActor normalizes an identity string so two spellings of the same
// Gas Town identity compare equal. The same identity arrives at bd in more
// than one spelling depending on which layer produced the string it was
// handed: a dotted alias like "gastown.mayor" gets its dot replaced wherever
// a dot is unsafe for that context — "__" in a session name, "_" in a Dolt
// table/database name, "-" elsewhere — and bd only ever sees the resulting
// string, never the substitution itself (ga-wzl83). None of ".", "_", "-"
// carries meaning in an identity string: each is always a positional
// separator between a rig and a role/agent name, never part of either name.
// Collapsing a run of them to one canonical separator lets two spellings of
// the same identity compare equal without weakening comparisons between
// genuinely different identities, whose non-separator characters still
// differ (e.g. "gastown.mayor" vs "gastown.dog-3" stay distinct).View on GitHub (pinned to 71377f2769)
Solutions
- Pass --force to the bd command if you genuinely need to modify the pinned issue
- Reconsider whether the operation should skip pinned issues (filter them out)
- Use 'bd show <id>' to confirm pin state and who/why it was pinned
- Ask the maintainer who pinned it before forcing
Example fix
// before bd close bd-anchor // blocked: pinned // after bd close bd-anchor --force // intentional override
Defensive patterns
Strategy: validation
Validate before calling
if issue.Pinned || issue.Status == types.StatusPinned {
return fmt.Errorf("%s is pinned; skipping (use --force deliberately)", issue.ID)
} Type guard
func isPinned(issue *types.Issue) bool { return issue != nil && (issue.Pinned || issue.Status == types.StatusPinned) } Try / catch
if err := closeIssue(id); err != nil {
if strings.Contains(err.Error(), "pinned") && forceAllowed {
return closeIssueForce(id)
}
return err
} Prevention
- Skip pinned issues in automation/bulk scripts by default
- Treat --force on a pinned issue as a deliberate, logged decision
- Check 'bd show <id>' pin state before closing stale issues
When it happens
Trigger: Update/close/assign on an issue with Pinned=true or Status='pinned' while force=false in the validator.
Common situations: Bulk scripts that iterate all open issues and hit pinned anchors; new contributors unaware an issue is intentionally pinned; automation closing stale issues that are pinned.
Related errors
- no store is open for this workspace
- 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)
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/33884697c1a0f562.
Report an issue: GitHub.