> For the complete documentation index, see [llms.txt](https://docs.convai.com/api-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/troubleshooting.md).

# 排查多角色会话问题

在 Unity 中运行多角色会话时，修复成员列表拒绝、就绪失败、音频路由错误和命令错误。

大多数多角色问题都可归结为三个位置之一：SDK 在连接时构建的名册、运行时用于定位成员的标识，或者一个 `IConvaiOperation<T>` 会报错而不是完成的命令。请在下面找到完全匹配的消息或症状；每条都按其在 Unity 控制台中出现的原文引用，并在仅引用较长行开头时加以说明。

### 开始之前

* 确认 `IConvaiRoomConnectionService.CurrentMultiCharacterSession` 不是 `null` 在诊断任何其他问题之前先确认——下面若干症状只有在存在多角色会话后才适用。
* 请读取失败时的控制台行。下面的消息均为原文引用，匹配错了会导致错误的修复。
* 确认场景中有两个或更多 **处于激活且启用状态** `ConvaiCharacter` 在连接之前的组件。不活动或已禁用的角色会被悄悄排除在名册之外，而单个活动角色不会生成名册。

### 没有活动角色时连接失败

在构建任何名册之前都会先执行一项单独检查，不管场景拥有多少角色都一样。

| 症状                                              | 原因                                                                                                                      | 修复方法                                                                              | 验证           |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | ------------ |
| `ConvaiOperationException`: `无法连接，因为没有可用的活动角色。` | 当……时未解析到活动角色 `ConnectAsync` 运行——例如，所有拥有的角色都处于不活动或已禁用状态。不适用于 `JoinMultiCharacterRoomAsync`，它不需要活动角色，因为它加入的是另一个客户端已创建的房间。 | 至少激活一个 `ConvaiCharacter`，或者调用 `ConvaiManager.SetInitialCharacter` ，并在连接前传入一个活动角色。 | 连接尝试不再抛出此消息。 |

### 连接时名册被拒绝

当名册违反以下任一规则时，具有两个或更多活动且启用角色的场景会在任何请求到达 Convai 之前被拒绝。不活动或已禁用的 `ConvaiCharacter` 会在这些规则运行前被排除在名册之外，因此不会触发任何一条规则。

| 症状                                                                  | 原因                                                           | 修复方法                                                                                                                                                        | 验证                                                        |
| ------------------------------------------------------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- |
| `ConvaiOperationException`：消息以 `一个 Convai 房间最多支持 50 个角色`            | 超过 50 个活动且启用的 `ConvaiCharacter` 组件已注册到管理器。                   | 将活动角色缩减到 50 个或更少，或者使用 **Convai Manager > Characters Joining the Room** 只发送此对话所需的角色。                                                                         | 连接尝试不再抛出，并且 `CurrentMultiCharacterSession` 会被填充。          |
| `ConvaiOperationException`: `多角色名册包含空或重复的角色引用。`                     | 相同的 `ConvaiCharacter` 组件被注册了两次，或者空引用传递到了名册构建器。               | 每个组件只注册一次。使用第二个组件实例来添加同一角色的克隆。                                                                                                                              | `session.Characters` 为每个不同的 `ConvaiCharacter` 实例恰好持有一个成员。 |
| `ConvaiOperationException`：消息以 `“<name>”和“<name>”都使用了 Character ID` | 两个活动且启用的角色共用同一个 Character ID——通常是因为其中一个是从另一个复制出来的。           | 请在 Convai 仪表板中为副本分配它自己的 Character ID。参见 [角色身份](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/character-identity.md). | 连接尝试不再抛出此消息。                                              |
| `ConvaiOperationException`: `多角色房间中的每个角色都需要一个 Character ID。`        | 一个活动且启用的 `ConvaiCharacter` 在场景中的……的值为空 **Character ID** 字段中。 | 请在场景中每个活动角色上设置该字段，并在任何不活动角色在你稍后激活并通过……添加之前，也要设置该字段 `AddCharacterAsync`.                                                                                     | 连接尝试不再抛出此消息。                                              |
| `ConvaiOperationException`: `角色会话 ID 在多角色名册中必须唯一。`                  | 两个角色解析到了相同的 character-session ID。                            | 为每个实例指定不同的 character-session ID，或者省略它，这样 SDK 就会为该实例开启新的对话。                                                                                                  | 连接尝试不再抛出此消息。                                              |

{% hint style="info" %}
“ `ConvaiOperationException` 针对这四种情况中任意一种抛出的异常都会携带上述完全相同的消息，但其 `代码` 始终是 `ConnectionFailed` 在调用处——原始会话错误码在那里不可见。参见 [连接 API 参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/connection-api-reference.md#connect-time-roster-validation).
{% endhint %}

### 运行时和寻址问题

| 症状                                          | 原因                                                                                                        | 修复方法                                                                                                                                                                                                                                           | 验证                                                             |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
| 游戏运行期间启用的角色从不加入，而且不会抛出异常                    | 房间连接时恰好只有一个活动角色，因此它在打开时没有可加入的名册。控制台会在每次连接时警告一次： `“<name>”无法加入此对话：该房间是为单个角色打开的，因此没有可加入的名册。下次房间连接时它将被包含进去。` | 请让你希望在场景中处于活动状态的每个角色 **在……之前** 房间连接时，因此会以可加入的名册打开。参见 [角色的加入和离开](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/update-the-roster.md#a-single-character-room-cant-grow).                                  | 控制台会记录 `“<name>”无需重新连接就加入了房间。` 改为此项。                           |
| 我预期的某个角色缺失于 `session.Characters`            | 该角色的 `游戏对象` 或 `ConvaiCharacter` 组件在房间连接时处于不活动或已禁用状态。SDK 会悄悄将不活动角色排除在启动名册之外——不会抛出异常，也不会有验证消息指出缺失的角色。       | 在连接前激活该角色，或者让它在游戏运行中启用时自动加入，或者通过 [角色的加入和离开](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/update-the-roster.md#add-a-character-to-the-roster).                                                          | 该角色出现在 `session.Characters` ，其中有一个 `成员 ID`.                    |
| 一个成员会保持 `启动中` 并且永远不会到达 `就绪`                 | Convai 尚未就该成员给出任何状态报告，或者其配置流程卡住了。                                                                         | 订阅 `CharacterStatusChanged` 并检查 `ProvisioningStatus` 和 `FailureCode` 针对该成员。 `WaitUntilReadyAsync` 只报告初始角色；参见 [房间就绪状态](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/readiness-and-partial-dispatch.md). | 该成员的 `状态` 变为 `就绪` 或 `Failed` ，其中有一个 `FailureCode` 你可以对其进行操作。   |
| 玩家输入到达了并非玩家本意所指的角色                          | 代码缓存了过期的 `成员 ID`，或者在目标已解析之后、输入发送之前交互目标发生了变化。                                                              | 读取 `MultiCharacterRoomSession.ActiveMembershipId` 在处理输入前立即获取，而不是缓存成员引用。                                                                                                                                                                        | 你的代码所定位的成员匹配 `当前成员 ID` 在输入发送的那一刻。                              |
| 同一角色的两个克隆被解析为一个对象，或者本应仅作用于一个克隆的事件看起来却影响了两个  | 查找表或音频映射以 `角色 ID`为键，而该值在名册中并不唯一。                                                                          | 将查找表改以 `成员 ID` 用于寻址，并以 `参与者标识` 用于音频。参见 [角色身份](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/character-identity.md).                                                                                     | 每个克隆的 `成员 ID` 和 `参与者标识` 驱动不同的行为。                               |
| `CurrentMultiCharacterSession` 是 `null` 连接后 | 连接响应没有同时携带名册和房间会话 ID——这对于单角色房间、未返回多角色数据的连接，或者拥有两个角色但在连接时只有一个处于活动且启用状态的场景来说都是预期情况。                         | 确认场景中有两个或更多 **处于激活且启用状态** `ConvaiCharacter` 在连接前的组件。                                                                                                                                                                                           | `CurrentMultiCharacterSession` 不是 `null` 和 `角色` 为每个活动角色持有一个成员。 |

### 名册和目标命令失败

对……的每个操作 `IConvaiRoomConnectionService` 都会使其出错 `IConvaiOperation<T>` 而不是同步抛出——请在等待的任务上处理异常。

| 症状                                                            | 原因                                                                            | 修复方法                                                | 验证                                                                       |
| ------------------------------------------------------------- | ----------------------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------------------ |
| `CharacterRosterUpdateException` ，代码为 `roster_epoch_mismatch` | 另一个已被接受的名册命令先一步更改了名册。                                                         | 读取 `session.RosterEpoch` 并使用当前值重试该修改。               | 重试后的调用完成且不会抛出该异常。                                                        |
| `CharacterRosterUpdateException` ，代码为 `unauthorized_sender`   | Convai 未将此客户端视为有权更改该房间名册。                                                     | 请确认该命令是从 Convai 认可的、属于此房间的客户端发送的，然后重试。              | 重试后的调用完成，名册反映出预期的更改。                                                     |
| `TimeoutException`: `等待角色名册更新确认时超时。`                          | 在……之后 15 秒内未收到确认 `AddCharacterAsync` 或 `RemoveCharacterAsync`.                | 重新读取 `session.Characters` 再重试之前——Convai 可能已经应用了该更改。 | `session.Characters` 反映出你预期的名册。                                          |
| `TimeoutException`: `等待交互目标确认时超时。`                            | 在……之后 10 秒内未收到确认 `SetInteractionTargetAsync` 或 `ClearInteractionTargetAsync`. | 重新读取 `当前成员 ID` 和 `路由 epoch` 再重试之前。                  | `当前成员 ID` 反映出你预期的目标。                                                     |
| `ArgumentException`: `此本地角色实例已是当前房间的成员。添加克隆时请使用另一个实例。`        | 相同的 `ConvaiCharacter` 组件实例被传递给了 `AddCharacterAsync` 两次。                       | 使用第二个 `ConvaiCharacter` 应使用一个实例来添加克隆，而不是重用现有实例。     | `AddCharacterAsync` 成功，并返回一个新的成员，位于 `CharacterRosterUpdateResult.Added`. |
| `ArgumentException`: `替换目标不属于当前房间。`                           | “ `replacementTargetMembershipId` 传递给 `RemoveCharacterAsync` 与任何当前成员都不匹配。     | 重新读取 `session.Characters` 并传入一个 `成员 ID` 当前在名册中的。    | 调用完成，并且 `当前成员 ID` 反映出替换结果。                                               |
| `ArgumentException`: `替换目标不能是正在移除的成员资格。`                      | `replacementTargetMembershipId` 等于传递给……的成员。 `RemoveCharacterAsync`.           | 请传入另一个成员作为替换对象，或者在目标应被清除时省略它。                       | 调用完成且不会抛出该异常。                                                            |

{% hint style="warning" %}
除……之外，后端名册错误代码还可能存在其他值 `roster_epoch_mismatch` 和 `unauthorized_sender`。将客户端此前未见过的任何代码都视为无法识别的后端拒绝，并同时记录 `CharacterRosterUpdateException.Code` 和 `消息` 而不是自行推断原因。
{% endhint %}

### 仍然被阻塞

在上报之前请收集以下信息：准确的控制台消息、该 `房间会话 ID` 受影响房间的……、当前的 `花名册 epoch` 和 `路由 epoch` 来自 `MultiCharacterRoomSession`，以及同一调用在新建房间中是否成功。请将该症状与 [Live API 故障排查表](/api-docs/zh/api-can-kao/core-api-reference/live-apis-beta/multi-character-sessions.md#verify-and-troubleshoot) ——源自后端的拒绝也会出现在那里，并在协议层面进行描述。

### 相关页面

{% content-ref url="/pages/1de47e20d64086de6ea2148c4871a665eec92182" %}
[多角色会话工作原理](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/how-multi-character-sessions-work.md)
{% endcontent-ref %}

{% content-ref url="/pages/f4a7ab842bf490bd88b4adbd8fbf66d1757f124e" %}
[房间会话参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/room-session-reference.md)
{% endcontent-ref %}

{% content-ref url="/pages/634a0663b206a73fe4e2113edd3096e48b351d9a" %}
[连接 API 参考](/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/connection-api-reference.md)
{% endcontent-ref %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.convai.com/api-docs/zh/cha-jian-yu-ji-cheng/convai-unity-sdk/features/multi-character-sessions/troubleshooting.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
