gastownhall/beads · error
%s
Error message
%s
What it means
This error surfaces the missingExplicitStateMapMessage: pushing to Linear requires explicit linear.state_map.* entries because defaults are safe for pulling but too ambiguous for mutations. It fires when config is nil or has no ExplicitStateMap entries, even though the state cache was populated.
Source
Thrown at internal/linear/mapping.go:380
// when state_map values are custom status names like "review").
if parsed == types.StatusOpen && normalizedMapped != "open" {
return false
}
return true
}
return false
}
// ResolveStateIDForBeadsStatus returns the unique Linear workflow state ID to
// use when pushing the given beads status. Push only trusts explicit
// linear.state_map.* entries; defaults are safe for pull but too ambiguous for
// mutation.
func ResolveStateIDForBeadsStatus(cache *StateCache, status types.Status, config *MappingConfig) (string, error) {
if cache == nil || len(cache.States) == 0 {
return "", fmt.Errorf("no workflow states found")
}
if config == nil || len(config.ExplicitStateMap) == 0 {
return "", fmt.Errorf("%s", missingExplicitStateMapMessage)
}
// Outbound override: an explicit linear.outbound_state_map.<status> entry
// names the exact Linear workflow state to push to and short-circuits the
// name/type matching below. This is the escape hatch when multiple Linear
// states share a type (e.g. "In Progress" and "In Review" are both
// "started") and the type-based fallback would otherwise be ambiguous.
if outboundName, ok := config.OutboundStateMap[strings.ToLower(strings.TrimSpace(string(status)))]; ok {
want := strings.ToLower(strings.TrimSpace(outboundName))
for _, state := range cache.States {
if strings.ToLower(strings.TrimSpace(state.Name)) == want {
return state.ID, nil
}
}
return "", fmt.Errorf("linear.outbound_state_map.%s = %q does not match any Linear workflow state", status, outboundName)
}
var nameMatches []StateView on GitHub (pinned to 71377f2769)
Solutions
- Run 'bd linear link' to configure the status mapping interactively.
- Add explicit linear.state_map entries to the config mapping each beads status to a Linear state name or type.
- Ensure the MappingConfig passed to the resolver is non-nil and its ExplicitStateMap is populated.
- Validate the config at startup (ValidatePushStateMappings) before attempting a push.
- Check the config file for typos in the linear.state_map key prefix.
Example fix
// before # config.toml [linear] api_key = "..." # no state_map section // after # config.toml [linear.state_map] open = "Backlog" in_progress = "In Progress" closed = "Done"
Defensive patterns
Strategy: validation
Validate before calling
func requireExplicitStateMap(cfg *linear.MappingConfig) error {
if cfg == nil || len(cfg.ExplicitStateMap) == 0 {
return fmt.Errorf("linear.state_map not configured; run 'bd linear link' before pushing")
}
return nil
} Type guard
func pushMappingConfigured(cfg *linear.MappingConfig) bool {
return cfg != nil && len(cfg.ExplicitStateMap) > 0
} Try / catch
stateID, err := linear.ResolveStateIDForBeadsStatus(cache, status, cfg)
if err != nil && strings.Contains(err.Error(), "bd linear link") {
return fmt.Errorf("push blocked: %v", err)
} Prevention
- Run 'bd linear link' before any push operation in a new workspace.
- Validate push mappings at startup (e.g. ValidatePushStateMappings).
- Never hand-edit config to remove the [linear.state_map] section.
- Treat pull success as insufficient — push requires explicit mappings.
- Keep config under version control so deletions are reviewed.
When it happens
Trigger: Calling ResolveStateIDForBeadsStatus with a populated cache but config == nil or len(config.ExplicitStateMap) == 0 — the user never ran 'bd linear link' or removed the state_map section from configuration.
Common situations: Fresh install where pull works with defaults but the first push fails; hand-edited config deleting linear.state_map keys; upgrading from a version that did not require explicit push mappings.
Related errors
- linear.state_map has no configured Linear state for beads st
- no workflow states found
- linear.outbound_state_map.%s = %q does not match any Linear
- linear.state_map maps beads status %q to multiple Linear sta
- linear.state_map type fallback is ambiguous for beads status
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/1ddc21b1359a1dab.
Report an issue: GitHub.