跳转到内容

附录 F · 报错排查

约 14 分钟

写世界过程中冒出来的红字、卡点、“按了没反应”,绝大多数都能在下面这几张表里查到。每条按这个格式:

**报错关键字 / 现象**
> 完整样例(如有)
可能原因:1. ... 2. ...
排查步骤:1. ...
相关章节:[X 章 · 节](slug)
相关词条:[词条](/appendix/glossary/#anchor)

分六组:

  • F.1 Unity Console 编译错——红字停在编辑器里、不让进 Play。
  • F.2 Udon 运行时异常——能进世界,但脚本一执行就出问题。
  • F.3 同步与多人——表现差异在客户端之间。
  • F.4 Build & SDK 上传——Build & Test / Build & Publish / SDK Validation。
  • F.5 资源、材质、Quest——粉色材质、Shader 兼容、APK 限制。
  • F.6 工具链 / 环境——VCC、Unity Hub、MAX_PATH、Library 损坏。

第 12 章末尾的排坑顺序和第 40 章末尾的排错清单是这份附录的”主入口”——撞墙的时候先按那两份顺序走一遍,再回来这里查具体报错。


红字停在 Unity 编辑器,不让进 Play Mode。一般是脚本编译过不去。

script class cannot be found / GUID 失效

Section titled “script class cannot be found / GUID 失效”

The associated script can not be loaded. Please fix any compile errors and assign a valid script.

可能原因:

  1. Console 上方还有其他红字编译错(脚本编译失败 → 这条是”找不到编译产物”的连锁反应)。
  2. Library/ScriptAssemblies 目录损坏(Unity 中途崩溃、被杀进程后常见)。
  3. 资源 GUID 漂了(手动复制 .cs 但没复制 .meta,或 git 冲突时把 .meta 解错)。

排查步骤:

  1. 先把上面其他红字编译错修掉,本错通常自动消失。
  2. 如果上面没有别的红字:关闭 Unity,删掉项目根的 Library/ScriptAssemblies 文件夹,重开。
  3. 如果还在,看出问题的 .cs 旁边有没有同名 .meta。没有的话从 git 历史拉回来。

相关章节:第 40 章 · 第六节 · 常见错误的速读表。 相关词条:Library/ScriptAssemblies.meta 文件

[UdonSharp] System.IO.File.ReadAllText is not exposed in Udon.

可能原因:调了不在 VRChat Class Exposure Tree 白名单上的 API。常见的有 System.IO.* / System.Net.* / System.Reflection.* / System.Threading.* / LINQ

排查步骤:

  1. 打开 VRChat SDK Control Panel → Udon → Class Exposure Tree,确认目标 API 不在白名单。
  2. 附录 D.1 找替代写法(持久化用 Player Persistence API、外部数据用 VRCUrl + VRCStringDownloader、列表用 DataList,等等)。

相关章节:第 12 章 · 第一类:白名单里没有的 API。 相关词条:VRCUrlPlayer Persistence API

Script without UdonSharpBehaviour definition should not have an associated UdonSharpProgramAsset

Section titled “Script without UdonSharpBehaviour definition should not have an associated UdonSharpProgramAsset”

可能原因:在 Assets/Scripts/ 这类普通目录下放了一个不继承 UdonSharpBehaviour 的纯 C# 类(典型是装常量的 static class)。UdonSharp 编译器扫到它就抗议。

排查步骤:

  1. 把这个文件挪到 Assets/Plugins/ 下。Plugins 走另一条编译路径,UdonSharp 不会要求文件必须是 UdonSharpBehaviour
  2. 引用方式不变,仍然能从 UdonSharp 脚本里 using 它、调它的常量。

相关章节:第 12 章 · 纯静态类必须放在 Plugins/ 文件夹。 相关词条:Plugins/UdonSharpProgramAsset

: MonoBehaviour 报错(脚本基类用错)

Section titled “: MonoBehaviour 报错(脚本基类用错)”

把外部教程的 C# 文件直接拖进 VRChat 项目,里面写着 public class Foo : MonoBehaviour

可能原因:UdonSharp 项目里能挂上 VRChat 物体并被 Udon 执行的脚本,必须继承 UdonSharpBehaviour,不是 MonoBehaviour

排查步骤:

  1. : MonoBehaviour 改成 : UdonSharpBehaviour
  2. 检查脚本里有没有用到 UdonSharp 不支持的 C# 特性(asyncyieldinterface、自定义泛型……),按 附录 D.2 替换。

相关章节:第 12 章 · UdonSharp 的脾气附录 D · UdonSharp 限制。 相关词条:UdonSharpBehaviour

UdonSharp 编译器特性限制(async / yield / 接口 / 自定义泛型 / try-catch

Section titled “UdonSharp 编译器特性限制(async / yield / 接口 / 自定义泛型 / try-catch)”

编译器红字会直接告诉你哪个特性不支持,例如 UdonSharp does not currently support 'try-catch'

可能原因:UdonSharp 编译器自身能力的边界。常见的有 async / awaityield return、自定义泛型、interfaceevent、自定义 indexer / operator overload、按「普通数据类」思路 new 的对象、switch 表达式等。

排查步骤:按 附录 D.2 一条条比对,每条都给了替代:

  • “过 N 秒做一件事”用 SendCustomEventDelayedSeconds(nameof(M), N)
  • 没有 try-catch → 写之前判空 if (x != null)
  • 没有 List<T> / Dictionary → 优先 T[],不够用上 DataList / DataDictionary

相关章节:第 12 章 · 第二类。 相关词条:SendCustomEventDelayedSecondsDataList / DataDictionary / DataToken


能进世界、Console 没编译错,但脚本一执行就出问题。

NullReferenceException: Object reference not set to an instance of an object
DoorController.Interact () (at Assets/Scripts/DoorController.cs:18)

可能原因:

  1. Inspector 里某个 public 字段没拖引用(先查这项)。
  2. 调了一个返回 null 的方法(GetComponent<X>() 没找到 X 组件),没判空就接着用。
  3. 引用的对象在运行中被销毁了(这种通常报 MissingReferenceException,见下条)。

排查步骤:

  1. 双击红字跳到对应 .cs:行号,看那一行用了哪个变量。
  2. 回 Unity 编辑器看挂这个脚本的 GameObject,Inspector 里那个变量对应的引用槽是不是 None
  3. 如果是 GetComponent 之类的返回值,加 if (x != null) 提前判空(参考 第 40 章 · 第七节)。
  4. UdonSharp 没有 try-catch——一发生 NRE 当前事件就中断、后面代码不再执行。“按按钮没反应”很常是 Interact 第三行 NRE 了,第四行根本没机会跑。

相关章节:第 40 章 · 第一节 Console 是免费的。 相关词条:NullReferenceException / NRE

UdonBehaviour will be halted(Udon VM 异常自停)

Section titled “UdonBehaviour will be halted(Udon VM 异常自停)”
Error - [UdonBehaviour] An exception occurred during Udon execution,
this UdonBehaviour will be halted.
VRC.Udon.VM.UdonVMException: An exception occurred during EXTERN to
'VRCSDK3VideoComponentsBaseBaseVRCVideoPlayer.__GetTime__SystemSingle'.
---> System.NullReferenceException: ...

可能原因:当前 UdonBehaviour 抛了未捕获异常。Udon 的处理方式是只熄火当事 UdonBehaviour,不影响其他玩家、其他世界、其他脚本。被熄火的脚本上从此所有事件都不再触发,直到玩家重新进入世界。

“按一次有反应、再按一次没反应""门第一下能开、第二下不动”这类时灵时不灵的问题,多半是中间发生了一次 halted。

排查步骤:

  1. Console 右上角搜 halted,把所有这类异常一网打尽。
  2. ---> 后面的 InnerException,找真实根因(多数仍然是 NRE)。
  3. 堆栈里 EXTERN to '...' 那条会指出炸在哪个外部 API 调用上。结合调用上下文找到具体哪一行的引用是 null
  4. 修法和 NRE 一样:调用前判空。

相关章节:第 40 章 · 第三节 Udon 异常自停。 相关词条:haltedEXTERN

The object of type 'GameObject' has been destroyed but you are still trying to access it.

可能原因:代码里 Destroy(...) 了一个对象,之后又通过原引用调用它。Unity 引用槽里的”对象已销毁”和 C# 的 null 不完全一样——它是一个伪 null(x != null 也可能被判为 false)。

排查步骤:

  1. 检查代码里有没有 Destroy()SetActive(false) 之后还在用同一个引用。
  2. VRChat 世界里通常更稳的做法是不要 Destroy 场景里预放好的物体,用 SetActive(false) 替代。
  3. 引用清空时显式赋 nulltarget = null;

相关章节:第 40 章 · 第六节 · 常见错误的速读表

[Udon] Cannot find method 'OnButtonPress' on UdonBehaviour 'GameButton (UdonBehaviour)'

可能原因:

  1. SendCustomEvent("OnButtonPress") 字符串方法名拼错了(少了大小写、写错了字母)。
  2. 目标方法是 private 的——SendCustomEvent 只认 public 方法。
  3. 目标脚本上根本没这个方法。

排查步骤:

  1. 把字符串方法名换成 nameof(OnButtonPress)——改名后编译器立刻提示,不用等运行时。
  2. 检查目标方法的可见性:要被 SendCustomEvent / SendCustomNetworkEvent 调用的方法必须 public
  3. 跨脚本调用时确认方法在的是不是你 Inspector 里拖的那个 GameObject。

相关章节:第 12 章 · 一些惯用法上的小差别附录 D.3 · 运行时行为差异。 相关词条:SendCustomEventnameof()

按按钮没反应(不报错也不打日志)

Section titled “按按钮没反应(不报错也不打日志)”

可能原因:

  1. 按钮所在 GameObject 没装 Collider,或装了但 Is TriggerInteract 的预期不匹配。
  2. 脚本没真的挂上去,或挂错了对象。
  3. 脚本上一次跑到一半就 halted 了——所以这一次根本没触发任何事件
  4. Interact 在 VRChat 里写法是 public override void Interact(),没写 override 编译能过但运行时不会被调用。

排查步骤:

  1. Interact() 第一行加 Debug.Log("[Door] Interact 被触发");,再 Build & Test。日志没出来 = 事件根本没到;出来了 = 事件到了但中间断了。
  2. Console 搜 halted,看有没有上一次留下的红字。
  3. 检查方法签名:Unity 标准方法(Start / Update)不写 override;VRChat 事件(Interact / OnPickup / OnPlayerJoined)必须写 public override

相关章节:第 13 章 · 第一步第 40 章 · 第二节 Debug.Log 放在三个位置

协程不工作 / yield return new WaitForSeconds(...) 编译过不去

Section titled “协程不工作 / yield return new WaitForSeconds(...) 编译过不去”

可能原因:UdonSharp 不支持 yield,普通 Unity 教程里的协程写法在这里走不通。

排查步骤:把协程改成 SendCustomEventDelayedSeconds

// 普通 Unity 协程
IEnumerator MyCoroutine()
{
yield return new WaitForSeconds(1f);
DoNext();
}
// UdonSharp 替代
public void DoLater()
{
SendCustomEventDelayedSeconds(nameof(DoNext), 1f);
}
public void DoNext() { /* ... */ } // 必须 public

相关章节:第 12 章 · 第二类附录 D.5 替代写法对照。 相关词条:SendCustomEventDelayedSeconds


表现差异出现在不同客户端之间。先去 附录 E · 网络同步决策表E.7 常见错配的对照对一眼,下面只列那张表上没展开的细节。

可能原因:脚本里改的是本地字段,没走网络。

排查步骤:

  1. 字段加 [UdonSynced]
  2. 脚本类上加 [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)](或 Continuous)。
  3. 改完字段后调 RequestSerialization()
  4. 非 Owner 在 OnDeserialization() 里读新值并刷新本地表现。

相关章节:第 28 章 · 同步变量四件套附录 E.2.2

可能原因:改字段的人不是 Owner——他改的值只在本机有效,Owner 那份的值下次同步过来就会盖掉。

排查步骤:改字段前先 Networking.SetOwner(Networking.LocalPlayer, gameObject),然后再改 [UdonSynced] 字段 + RequestSerialization()。或者发 SendCustomNetworkEvent(NetworkEventTarget.Owner, "改字段的方法") 让 Owner 自己改。

相关章节:第 27 章 · 给灯按钮加 SetOwner附录 E.3.2 什么时候要 SetOwner

可能原因:状态是用 SendCustomNetworkEvent 广播出去的——Late Joiner 收不到那次广播。

排查步骤:把”事件”翻译成”状态字段”。例如把”游戏开始过没有”做成 [UdonSynced] bool gameStarted,进 OnDeserialization 时刷 UI。如果非用事件不可,在 OnPlayerJoined 时由 Owner 主动定向发一份当前状态。

相关章节:第 29 章 · 同步变量自动追,事件追不上附录 E.5.2

RequestSerialization() 调了但别人没收到

Section titled “RequestSerialization() 调了但别人没收到”

可能原因:调用者不是 Owner——RequestSerialization 只有 Owner 调用才有效。

排查步骤:方法开头加 if (!Networking.IsOwner(gameObject)) return;。想让谁来改就先 SetOwner 给谁。

相关章节:第 28 章 · 第一步声明同步模式和同步字段附录 E.7


可能原因:项目模板不是 World,或者 Worlds SDK 包没装好。

排查步骤:

  1. 关闭 Unity,回 VCC(VRChat Creator Companion)打开项目。
  2. 检查项目类型是 World,不是 Avatar
  3. 在 VCC 项目页确认 VRChat World SDK 处于”已安装、版本最新”状态,必要时点 Update

相关章节:第 4 章 · 第三步:用 VCC 创建第一个世界项目第 5 章 · Build & Test 不工作时的检查清单

SDK 控制面板顶部红字:场景里没有 VRC Scene Descriptor

可能原因:当前打开的场景里没挂 VRC Scene Descriptor 组件。

排查步骤:

  1. Hierarchy 里检查有没有名为 WorldDescriptor(或类似)的 GameObject,身上是不是真挂了 VRC Scene Descriptor
  2. 没有的话:新建一个空物体,Add Component → VRC Scene Descriptor,把 Spawn 拖进 Spawns 数组的第 0 槽。
  3. 顺手检查:当前打开的场景是不是上传目标场景。换错场景的情况比想象中多。

相关章节:第 5 章 · 第四步:给场景一张身份证。 相关词条:VRC Scene DescriptorSpawns 数组

可能原因:

  1. Floor 身上的 Box Collider 被删掉了 / 关闭了。
  2. Spawn 的 Y 值落到地板下面去了。
  3. Floor 物体本身被禁用(Inspector 顶部的勾掉了)。

排查步骤:

  1. 选中 Floor,确认有 Box ColliderMesh Collider,并且勾着启用。
  2. 选中 Spawn,看 Transform 的 Y 是不是在 Floor 上方一点点(如 0.1 而不是 -1)。
  3. Build & Test 试。

相关章节:第 5 章 · Build & Test 不工作时的检查清单

可能原因:

  1. SDK 控制面板里没登录 VRChat 账号。
  2. 本机没装 VRChat 客户端(Steam 版或官方版都行)。
  3. 顶部 Build Target 切到了 Android 但本机 VRChat 是 PC 版。

排查步骤:

  1. SDK Control Panel 顶部 Authentication 标签,登一下账号。
  2. 顶部菜单 File → Build Settings,确认 PlatformWindows, Mac, Linux(PC 版)。
  3. 确认本机 VRChat 客户端能正常启动。

相关章节:第 5 章 · Build & Test 不工作时的检查清单第 41 章 · 第二节 Build & Test 是真正的本地客户端

SDK 控制面板 Builder 标签下方一行行红字,Quest 平台相关条目往往占多数。

可能原因:

  1. Shader 对 Android 过重或触发兼容性警告。
  2. 纹理超过 1K,移动端内存压力过高。
  3. 场景里有 Light 组件配置不合规、Reflection Probe 烘焙数据缺失。
  4. VRC Scene Descriptor 字段没填全。

排查步骤:

  1. 一条条点 Validation 里的红字,下方 Auto Fix 能修的就修。
  2. 不能 Auto Fix 的,按红字定位的对象修。
  3. PC 版 Validation 通过、Quest 版红一片是常态——Quest 严得多,参见 第 39 章 · 第五节 Quest 的几条硬规矩

相关章节:第 41 章 · 第四节 Friends 私密上传是最后一道关第 44 章 · 第六节 会被退回或下架的几条硬线。 相关词条:SDK ValidationCommunity Labs

This world has no Quest version(玩家端报错)

Section titled “This world has no Quest version(玩家端报错)”

可能原因:上传时只 Build 了 PC 平台,Quest 端的 Quest 玩家进不来。

排查步骤:

  1. File → Build Settings → Switch Platform → Android
  2. 等 Unity 重新导入资源(中等大小项目几分钟到十几分钟)。
  3. SDK Control Panel → Build & Publish 一次。
  4. 验证:进 VRChat 网页 / 客户端,世界详情应同时显示 PCAndroid 两个平台徽章。

相关章节:理解章 A · 跨平台 PC、Android(含 Quest)、iOS 各一份第 39 章 · 第七节 维护一份工程做两个版本


可能原因:Shader 丢失。Unity 在找不到对应 Shader 时用 Error Shader(紫粉色)兜底。常见情形:换平台后 Shader 不兼容、复制工程时 Shader 路径漂了、Shader 文件被误删。

排查步骤:

  1. 选中变粉的 Material,看 Inspector 顶部 Shader 栏,多半显示 Hidden/InternalErrorShader
  2. 临时救场:把 Shader 切回 Standard(PC)或 VRChat/Mobile/Standard Lite(Quest)。
  3. 根因:Project 里搜原本的 Shader 文件还在不在;不在的话从素材包重新导入。

相关章节:第 9 章 · 调了但看不出来时第 39 章 · 第二节 Quest 强烈建议用 VRChat Mobile Shader。 相关词条:ShaderVRChat Mobile Shader

可能原因:

  1. Light Mode 设置和场景里物体 Static 标记不一致。
  2. 没有任何 MixedBaked 光,且关掉了 Auto Generate
  3. Lightmap 还没烘焙完成。
  4. Quest 平台用了 Realtime Light Mode(不支持)。

排查步骤:

  1. 场景里至少留一盏 Directional Light 设为 Mixed,把要参与烘焙的物体全部勾上 Static
  2. Window → Rendering → Lighting → Generate Lighting,等烘焙完成。
  3. Quest:Lighting Mode 切到 Subtractive,参考 第 39 章 · 第三节

相关章节:第 36 章 · 烘焙一次 Lightmap第 39 章 · 第三节。 相关词条:LightmapSubtractive

Quest 上传被拒:纹理 / Shader / Triangle 数超规

Section titled “Quest 上传被拒:纹理 / Shader / Triangle 数超规”

可能原因:Quest 平台对 Shader 复杂度、纹理总大小、Triangle、Material 数等都有硬上限。SDK Validation 会一行行列出来。

排查步骤:按 SDK Validation 的具体提示一条条修:

  1. 纹理:超过 1K 的批量改 Max Size = 1024512(Texture Inspector 顶部),移动端包体还要压到 100 MB 以内。
  2. Shader:把高成本或 PC 专用 Shader 优先替换为移动端友好的 Mobile/VRChat/LightmappedVRChat/Mobile/* 系列。
  3. Triangle:Mesh 用 Mesh Decimator 或建模软件减面。
  4. 整体读 第 39 章 · 第五节第 44 章 · 第六节

相关章节:第 39 章第 44 章 · 第六节。 相关词条:ASTCVRChat Mobile Shader

可能原因:常见瓶颈按出现频次排:

  1. Draw Call / Batches 过高——材质数太多,没启用 GPU Instancing / Static Batching。
  2. 实时光太多——VRChat 推荐主光烘焙、动态光用 Light Probe。
  3. 镜子 / VideoPlayer 单独算账——它们各自相当于额外渲染一次场景。
  4. Overdraw 高——半透明物体堆叠。

排查步骤:

  1. Game 面板右上 Stats,记下 Batches / SetPass calls / Tris / Verts
  2. Window → Analysis → Profiler 进 Play Mode,看 CPU / GPU 栏哪条最高。
  3. 第 38 章 · 第九节 性能优化的优先级 一条条对。

相关章节:第 38 章 · 全章第 36 章 · 实时光的开销,要克制。 相关词条:Draw Call / BatchesGPU InstancingProfiler


VCC 找不到 Unity / 启动卡在右下角 / Console 红字一片(首启动卡点)

Section titled “VCC 找不到 Unity / 启动卡在右下角 / Console 红字一片(首启动卡点)”

排查步骤:直接对 第 4 章 · 启动卡点速查。常见三类:

  • VCC 找不到 Unity:手动指定 Unity Hub → 安装 → 添加 → 选官方指定版本
  • 启动卡在右下角:等就行(Library 第一次构建慢);过 30 分钟还在卡,关 Unity 删 Library/,重开。
  • Console 红字一片:多半是 Unity 版本错。回 VCC 看官方钉死的版本。

相关章节:第 4 章 · 启动卡点速查

MAX_PATH / 中文路径 / 文件存在但读不到 / .meta 找不到对应资源

Section titled “MAX_PATH / 中文路径 / 文件存在但读不到 / .meta 找不到对应资源”

可能原因:Windows 默认路径长度上限 260 字符,VRChat 项目里 Library/ 下的缓存路径 + 资产相对路径加起来很容易撞上限。表现是部分 .meta “看着在但 Unity 找不到对应资源”、Material 引用混乱。

排查步骤:

  1. 把项目挪到短路径下,如 D:\vrc\MyWorld 而不是 C:\Users\长用户名\OneDrive\桌面\VRChat 项目\我的世界\
  2. 路径里别带中文(部分 .NET API 还是会因编码出问题)。
  3. Windows 10 1607+ 可以全局开 LongPathsEnabled 注册表项,但不要把它当救命药——挪短路径更稳。

相关章节:第 4 章 · 第三步:用 VCC 创建第一个世界项目。 相关词条:MAX_PATH

Library 损坏 / 切平台后 Unity 不正常

Section titled “Library 损坏 / 切平台后 Unity 不正常”

切到 Android 后场景一片粉、Console 飘红、Material 引用全乱。

可能原因:Unity 的 Library/ 目录是平台相关的二进制缓存。切平台时 Unity 会重建一部分缓存;过程中崩溃 / 杀进程会让 Library/ 处于半损坏状态。

排查步骤:

  1. 关闭 Unity。
  2. 删除项目根的 Library/ 整个目录(不要删 Assets/ / Packages/ / ProjectSettings/)。
  3. 重开 Unity,让它从头构建 Library(5–30 分钟,看项目大小)。
  4. Library/ 已在 .gitignore 里,删了不影响 git 仓库。

相关章节:第 42 章 · 第二节 写一份 Unity .gitignore。 相关词条:Library/ScriptAssemblies.gitignore

可能原因:.unity 是 YAML 格式但内部全是 GUID 引用、行号细碎,普通 git merge 处理不好。

排查步骤:

  1. 打开 Edit → Project Settings → Editor,把 Asset Serialization Mode 设为 Force Text
  2. 配 Git 用 UnityYAMLMerge 处理 .unity.prefab 的合并。
  3. 团队协作时按”一个场景同一时间只一个人改”原则降低冲突频率。

相关章节:第 42 章 · 第一节 先调两个 Unity 设置第 42 章 · 第五节 场景文件冲突用 UnityYAMLMerge。 相关词条:Smart Merge / UnityYAMLMerge


快速导航:读到一句话,去哪一节

Section titled “快速导航:读到一句话,去哪一节”
看到这种关键词直接跳哪
NullReferenceException / 红字带 at Assets/...:行号F.2 · NRE
halted / UdonVMExceptionF.2 · halted
is not exposed in UdonF.1 · 白名单
MonoBehaviour 报错F.1 · MonoBehaviour
script class cannot be foundF.1 · GUID 失效
UdonSharpProgramAsset 警告F.1 · 静态类要进 Plugins
Cannot find method ... on UdonBehaviourF.2 · SendCustomEvent 找不到方法
MissingReferenceExceptionF.2 · MissingReferenceException
自己看到、别人没看到F.3 · 同步漏配
后来加入的人没看到当前状态F.3 · Late Joiner 修法
顶部菜单找不到 VRChat SDKF.4 · 找不到 SDK 菜单
Build & Test 没反应 / Scene Descriptor 缺失 / 进世界往下掉F.4 · Build & Test 卡点
上传前 Validation 红字F.4 · SDK Validation
This world has no Quest versionF.4 · 没有 Quest 版本
材质变粉F.5 · 粉色材质
烘焙完场景全黑F.5 · 烘焙黑屏
帧率低 / Stats 红F.5 · 性能瓶颈
MAX_PATH / 中文路径F.6 · 路径长度
切平台后 Unity 异常F.6 · Library 损坏

外部参考: