{"record":{"id":"4333c3e8b6004c88","repo":"gastownhall/beads","slug":"linear-state-map-maps-beads-status-q-to-multiple","errorCode":null,"errorMessage":"linear.state_map maps beads status %q to multiple Linear states: %s","messagePattern":"linear\\.state_map maps beads status %q to multiple Linear states: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/linear/mapping.go","lineNumber":413,"sourceCode":"\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, \", \"))\n\t}\n\n\tvar typeMatches []State\n\tfor _, state := range cache.States {\n\t\tmapped, ok := config.ExplicitStateMap[strings.ToLower(strings.TrimSpace(state.Type))]\n\t\tif ok && stateMapMatchesStatus(mapped, status) {\n\t\t\ttypeMatches = append(typeMatches, state)\n\t\t}\n\t}\n\tif len(typeMatches) == 1 {\n\t\treturn typeMatches[0].ID, nil\n\t}\n\tif len(typeMatches) > 1 {\n\t\tnames := make([]string, 0, len(typeMatches))\n\t\tfor _, state := range typeMatches {\n\t\t\tnames = append(names, state.Name)\n\t\t}\n\t\treturn \"\", 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)","sourceCodeStart":395,"sourceCodeEnd":431,"githubUrl":"https://github.com/gastownhall/beads/blob/71377f276968b452ee607177637970a4ff888584/internal/linear/mapping.go#L395-L431","documentation":"Multiple Linear workflow states have explicit linear.state_map entries that both match the beads status being pushed (matched by state name), so the resolver cannot pick a unique target and refuses to mutate. Pushes require an unambiguous mapping.","triggerScenarios":"Calling ResolveStateIDForBeadsStatus where nameMatches (states whose explicit linear.state_map.<state-name> entry matches the status) contains 2+ states — e.g. linear.state_map.'Todo'='open' and linear.state_map.'Backlog'='open'.","commonSituations":"Configuring several Linear states (e.g. 'Todo' and 'Backlog') to the same beads status 'open'; copy-pasting state_map blocks for every state in the workspace.","solutions":["Map each beads status to at most one Linear state name in linear.state_map.","Use linear.outbound_state_map.<status> = \"<state name>\" to pin the push target for that status, which takes precedence.","Remove the redundant/incorrect state_map entry that creates the duplicate match.","Re-run 'bd linear link' to regenerate a one-to-one mapping."],"exampleFix":"// before\n[linear.state_map]\ntodo = \"open\"\nbacklog = \"open\"   # ambiguous: two names map to 'open'\n// after\n[linear.state_map]\nbacklog = \"open\"\n[linear.outbound_state_map]\nopen = \"Backlog\"   # explicit push target disambiguates","handlingStrategy":"validation","validationCode":"func checkNameAmbiguity(cfg *linear.MappingConfig, cache *linear.StateCache) error {\n\tfor status := range cfg.OutboundStateMap {\n\t\tmatches := 0\n\t\tfor _, s := range cache.States {\n\t\t\tif mapped, ok := cfg.ExplicitStateMap[strings.ToLower(strings.TrimSpace(s.Name))]; ok && mapped == status {\n\t\t\t\tmatches++\n\t\t\t}\n\t\t}\n\t\tif matches > 1 {\n\t\t\treturn fmt.Errorf(\"status %q matches multiple states by name; set outbound_state_map\", status)\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(), \"multiple Linear states\") {\n\treturn fmt.Errorf(\"ambiguous push mapping for %s: set linear.outbound_state_map.%s\", status, status)\n}","preventionTips":["Maintain a one-to-one mapping from Linear state names to beads statuses in linear.state_map.","Add a linear.outbound_state_map override whenever a workspace has multiple states mapped to one status.","Validate mappings at config load and fail fast before any push.","Avoid copy-pasting the same state_map value across many states.","Re-check mappings after adding custom states to the Linear workflow."],"tags":["linear","configuration","state-mapping","ambiguity"],"backgroundTag":"ambiguous-state-mapping","analyzedSha":"71377f276968b452ee607177637970a4ff888584","analyzedAt":"2026-08-30T18:55:39.744Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}