{"record":{"id":"8e1993c3d223bdcb","repo":"babalae/better-genshin-impact","slug":"error-8e1993","errorCode":null,"errorMessage":"切换角色：无法为未指定槽位生成补位角色","messagePattern":"切换角色：无法为未指定槽位生成补位角色","errorType":"exception","errorClass":"PartySetupFailedException","httpStatus":null,"severity":"error","filePath":"BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs","lineNumber":1074,"sourceCode":"            if (originalIndex < 0)\n            {\n                continue;\n            }\n\n            desired[index] = CreateTargetRole(index + 1, remaining[originalIndex].Name);\n            remaining.RemoveAt(originalIndex);\n        }\n\n        for (var index = 0; index < desired.Length; index++)\n        {\n            if (desired[index] != null)\n            {\n                continue;\n            }\n\n            if (remaining.Count == 0)\n            {\n                throw new PartySetupFailedException(\"切换角色：无法为未指定槽位生成补位角色\");\n            }\n\n            desired[index] = CreateTargetRole(index + 1, remaining[0].Name);\n            remaining.RemoveAt(0);\n        }\n\n        return desired.Select(role => role!).ToList();\n    }\n\n    private static int? FindFirstMismatchSlot(\n        IReadOnlyList<TargetRole> desiredRoles,\n        IReadOnlyList<TeamSlotSnapshot> currentSlots)\n    {\n        return desiredRoles\n            .OrderBy(role => role.Slot)\n            .FirstOrDefault(role =>\n                role.Slot > currentSlots.Count || !role.Matches(currentSlots[role.Slot - 1].Name))\n            ?.Slot;","sourceCodeStart":1056,"sourceCodeEnd":1092,"githubUrl":"https://github.com/babalae/better-genshin-impact/blob/a7cb36712dcb409be610257d877fcea3597e9d6b/BetterGenshinImpact/GameTask/Common/Job/SwitchCharacterStateMachineTask.cs#L1056-L1092","documentation":"BuildDesiredTeamRoles fills any still-empty desired slot from the 'remaining' list (characters present but not pinned to a target). If remaining is empty while a desired slot is still null, there are more slots to fill than characters available — an inconsistent state between expectedTeamCount and recognized members.","triggerScenarios":"After placing requested roles and restoring original-slot characters, a desired[index] is null and remaining.Count==0; i.e. currentSlots.Count (the array length) exceeds the number of name-bearing characters left to distribute.","commonSituations":"expectedTeamCount/_currentTeamSlots length disagrees with the actual number of recognized avatars (some slots had null names that were already consumed by the first projection, or a role consumed a name that was also pinned); a rebuild path shrank the team mid-operation; co-op controllable-slot count changed after the snapshot.","solutions":["Ensure _expectedTeamCount and _currentTeamSlots stay consistent — recompute both from a single recognition pass.","Before BuildDesiredTeamRoles, filter out null-named slots or reconcile the count; do not build desired[] longer than available names.","If the team genuinely has fewer members, shrink the desired array rather than over-filling."],"exampleFix":"// before\nif (remaining.Count == 0)\n{\n    throw new PartySetupFailedException(\"切换角色：无法为未指定槽位生成补位角色\");\n}\n\n// after\nif (remaining.Count == 0)\n{\n    desired = desired.Where(role => role != null).ToArray() as TargetRole?[];\n    break;\n}","handlingStrategy":"validation","validationCode":"if (currentSlots.Count(slot => !string.IsNullOrWhiteSpace(slot.Name)) < requestedRoles.Count(r => r.Slot <= currentSlots.Count))\n{\n    throw new PartySetupFailedException(\"切换角色：可控角色数少于待填充槽位数，请重新识别队伍\");\n}","typeGuard":null,"tryCatchPattern":"try { await switchTask.Start(...); }\ncatch (PartySetupFailedException ex) when (ex.Message.Contains(\"无法为未指定槽位生成补位角色\"))\n{ _logger.LogError(ex, \"队伍槽位与识别到的角色数不一致\"); }","preventionTips":["Keep _expectedTeamCount and _currentTeamSlots consistent, both derived from one recognition pass.","Filter null-named slots before building desired roles.","Shrink the desired array to the available name count."],"tags":["party-setup","data-merge","invariant","switch-character"],"backgroundTag":null,"analyzedSha":"a7cb36712dcb409be610257d877fcea3597e9d6b","analyzedAt":"2026-08-13T16:44:57.548Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}