gastownhall/beads · error

linear.state_map has no configured Linear state for beads st

Error message

linear.state_map has no configured Linear state for beads status %q

What it means

After explicit name matching and the type fallback both fail, ResolveStateIDForBeadsStatus gives up with this error: the configured linear.state_map has no entry that matches any Linear state for the beads status being pushed. The push cannot proceed without knowing which Linear state to move the issue to.

Source

Thrown at internal/linear/mapping.go:434

	var typeMatches []State
	for _, state := range cache.States {
		mapped, ok := config.ExplicitStateMap[strings.ToLower(strings.TrimSpace(state.Type))]
		if ok && stateMapMatchesStatus(mapped, status) {
			typeMatches = append(typeMatches, state)
		}
	}
	if len(typeMatches) == 1 {
		return typeMatches[0].ID, nil
	}
	if len(typeMatches) > 1 {
		names := make([]string, 0, len(typeMatches))
		for _, state := range typeMatches {
			names = append(names, state.Name)
		}
		return "", fmt.Errorf("linear.state_map type fallback is ambiguous for beads status %q across Linear states: %s. Set linear.outbound_state_map.%s = \"<state name>\" to disambiguate", status, strings.Join(names, ", "), status)
	}

	return "", fmt.Errorf("linear.state_map has no configured Linear state for beads status %q", status)
}

// ParseBeadsStatus converts a status string to types.Status.
func ParseBeadsStatus(s string) types.Status {
	switch strings.ToLower(s) {
	case "open":
		return types.StatusOpen
	case "in_progress", "in-progress", "inprogress":
		return types.StatusInProgress
	case "blocked":
		return types.StatusBlocked
	case "closed", "done":
		return types.StatusClosed
	case "deferred":
		return types.StatusDeferred
	case "pinned":
		return types.StatusPinned
	case "hooked":

View on GitHub (pinned to 71377f2769)

Solutions

  1. Add a linear.state_map entry for the missing beads status (by Linear state name or type).
  2. Run 'bd linear link' to regenerate a complete status mapping.
  3. Check the status key spelling on the left side of linear.state_map (use lowercase beads statuses: open, in_progress, closed).
  4. Verify which status is actually being pushed (log it) and confirm it is one you intended to map.

Example fix

// before
[linear.state_map]
open = "Backlog"   # in_progress not mapped
// after
[linear.state_map]
open = "Backlog"
in_progress = "In Progress"
closed = "Done"
Defensive patterns

Strategy: validation

Validate before calling

func validateAllStatusesMapped(cfg *linear.MappingConfig, cache *linear.StateCache, statuses []types.Status) error {
	for _, st := range statuses {
		if _, err := linear.ResolveStateIDForBeadsStatus(cache, st, cfg); err != nil {
			return fmt.Errorf("status %s not mapped for push: %w", st, err)
		}
	}
	return nil
}

Try / catch

stateID, err := linear.ResolveStateIDForBeadsStatus(cache, status, cfg)
if err != nil && strings.Contains(err.Error(), "no configured Linear state") {
	return fmt.Errorf("status %q is not mapped; add it to [linear.state_map] or run 'bd linear link'", status)
}

Prevention

When it happens

Trigger: Calling ResolveStateIDForBeadsStatus where no state name and no state type in the cache has a linear.state_map entry matching the given types.Status — e.g. config only maps 'open' but the status being pushed is 'in_progress'.

Common situations: Partial state_map configuration covering only some statuses; pushing a newly introduced beads status that was never mapped; typos in the status key on the left side of state_map.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/660d77c296a4a33c. Report an issue: GitHub.