{"record":{"id":"9673c249ad27239e","repo":"gastownhall/beads","slug":"linear-outbound-state-map-s-q-does-not-match-a","errorCode":null,"errorMessage":"linear.outbound_state_map.%s = %q does not match any Linear workflow state","messagePattern":"linear\\.outbound_state_map\\.(.+?) = %q does not match any Linear workflow state","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/mapping.go","lineNumber":395,"sourceCode":"\t\treturn \"\", fmt.Errorf(\"no workflow states found\")\n\t}\n\tif config == nil || len(config.ExplicitStateMap) == 0 {\n\t\treturn \"\", fmt.Errorf(\"%s\", missingExplicitStateMapMessage)\n\t}\n\n\t// Outbound override: an explicit linear.outbound_state_map.<status> entry\n\t// names the exact Linear workflow state to push to and short-circuits the\n\t// name/type matching below. This is the escape hatch when multiple Linear\n\t// states share a type (e.g. \"In Progress\" and \"In Review\" are both\n\t// \"started\") and the type-based fallback would otherwise be ambiguous.\n\tif outboundName, ok := config.OutboundStateMap[strings.ToLower(strings.TrimSpace(string(status)))]; ok {\n\t\twant := strings.ToLower(strings.TrimSpace(outboundName))\n\t\tfor _, state := range cache.States {\n\t\t\tif strings.ToLower(strings.TrimSpace(state.Name)) == want {\n\t\t\t\treturn state.ID, nil\n\t\t\t}\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"linear.outbound_state_map.%s = %q does not match any Linear workflow state\", status, outboundName)\n\t}\n\n\tvar nameMatches []State\n\tfor _, state := range cache.States {\n\t\tmapped, ok := config.ExplicitStateMap[strings.ToLower(strings.TrimSpace(state.Name))]\n\t\tif ok && stateMapMatchesStatus(mapped, status) {\n\t\t\tnameMatches = append(nameMatches, state)\n\t\t}\n\t}\n\tif len(nameMatches) == 1 {\n\t\treturn nameMatches[0].ID, nil\n\t}\n\tif len(nameMatches) > 1 {\n\t\tnames := make([]string, 0, len(nameMatches))\n\t\tfor _, state := range nameMatches {\n\t\t\tnames = append(names, state.Name)\n\t\t}\n\t\treturn \"\", fmt.Errorf(\"linear.state_map maps beads status %q to multiple Linear states: %s\", status, strings.Join(names, \", \"))","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/mapping.go#L377-L413","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n[linear.outbound_state_map]\nin_progress = \"InProgress\"   # no such state\n// after\n[linear.outbound_state_map]\nin_progress = \"In Progress\"","handlingStrategy":"validation","validationCode":"func validateOutboundOverrides(cfg *linear.MappingConfig, cache *linear.StateCache) error {\n\tfor status, name := range cfg.OutboundStateMap {\n\t\tfound := false\n\t\tfor _, s := range cache.States {\n\t\t\tif strings.EqualFold(strings.TrimSpace(s.Name), strings.TrimSpace(name)) {\n\t\t\t\tfound = true\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\tif !found {\n\t\t\treturn fmt.Errorf(\"outbound_state_map.%s references unknown Linear state %q\", status, name)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"stateID, err := linear.ResolveStateIDForBeadsStatus(cache, status, cfg)\nif err != nil && strings.Contains(err.Error(), \"outbound_state_map\") {\n\treturn fmt.Errorf(\"fix linear.outbound_state_map: %v\", err)\n}","preventionTips":["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."],"tags":["linear","configuration","state-mapping","typo"],"backgroundTag":"unresolved-state-name","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}