gastownhall/beads · error
linear.outbound_state_map.%s = %q does not match any Linear
Error message
linear.outbound_state_map.%s = %q does not match any Linear workflow state
What it means
The outbound override linear.outbound_state_map.<status> names a Linear state that does not exist in the workspace's state cache (compared case- and whitespace-insensitively by name). The resolver rejects the push rather than guessing, because the override is meant to name one exact state.
Source
Thrown at internal/linear/mapping.go:395
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 []State
for _, state := range cache.States {
mapped, ok := config.ExplicitStateMap[strings.ToLower(strings.TrimSpace(state.Name))]
if ok && stateMapMatchesStatus(mapped, status) {
nameMatches = append(nameMatches, state)
}
}
if len(nameMatches) == 1 {
return nameMatches[0].ID, nil
}
if len(nameMatches) > 1 {
names := make([]string, 0, len(nameMatches))
for _, state := range nameMatches {
names = append(names, state.Name)
}
return "", fmt.Errorf("linear.state_map maps beads status %q to multiple Linear states: %s", status, strings.Join(names, ", "))View on GitHub (pinned to 71377f2769)
Solutions
- Correct the value of linear.outbound_state_map.<status> to exactly match a Linear state name (case-insensitive).
- List current Linear workflow states (re-sync the state cache) and pick a valid name.
- Remove the outbound override if it is unnecessary and rely on linear.state_map instead.
- Re-run 'bd linear link' after Linear-side renames to refresh mappings.
- Verify the override targets a state in the same team the integration is scoped to.
Example fix
// before [linear.outbound_state_map] in_progress = "InProgress" # no such state // after [linear.outbound_state_map] in_progress = "In Progress"
Defensive patterns
Strategy: validation
Validate before calling
func validateOutboundOverrides(cfg *linear.MappingConfig, cache *linear.StateCache) error {
for status, name := range cfg.OutboundStateMap {
found := false
for _, s := range cache.States {
if strings.EqualFold(strings.TrimSpace(s.Name), strings.TrimSpace(name)) {
found = true
break
}
}
if !found {
return fmt.Errorf("outbound_state_map.%s references unknown Linear state %q", status, name)
}
}
return nil
} Try / catch
stateID, err := linear.ResolveStateIDForBeadsStatus(cache, status, cfg)
if err != nil && strings.Contains(err.Error(), "outbound_state_map") {
return fmt.Errorf("fix linear.outbound_state_map: %v", err)
} Prevention
- Copy state names exactly as they appear in Linear (case-insensitive but spelling must match).
- Re-run 'bd linear link' or re-sync whenever Linear states are renamed.
- Validate overrides against the state cache at config load time.
- Keep overrides scoped to the team the integration targets.
- Use the state cache contents (not memory) as the source of truth for names.
When it happens
Trigger: Calling ResolveStateIDForBeadsStatus when config has an outbound_state_map entry for the status, but no State in cache.States has a matching Name — a typo, a renamed Linear state, or a state belonging to a different team.
Common situations: Linear admin renamed 'In Progress' to 'Active' while the beads config still references the old name; config copied from another workspace; trailing-space or casing mistakes the trim/lower comparison can't fix because the name simply doesn't exist.
Related errors
- no workflow states found
- %s
- linear.state_map maps beads status %q to multiple Linear sta
- linear.state_map type fallback is ambiguous for beads status
- linear.state_map has no configured Linear state for beads st
AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30).
Data as JSON: /api/errors/9673c249ad27239e.
Report an issue: GitHub.