TUKI0136 | Network events on a Behaviour whose sync mode is None | A Behaviour with [UdonBehaviourSyncMode(BehaviourSyncMode.None)] takes no part in network events. A SendCustomNetworkEvent to it is not accepted when it is sent, and its [NetworkCallable] methods are never called over the network. To use network events, set the sync mode to NoVariableSync (Sync). It compiles (it doesn’t halt) |
TUKI0104 | Not enough storage for variables | There’s a cap on the number of variables one program can use. |
TUKI0105 | Too many type argument expansions | Too many combinations were passed to a generic to expand them all |
TUKI0107 | A conflict between the sync mode and the variable | The [UdonBehaviourSyncMode] setting and the way [UdonSynced] is attached don’t match up. |
TUKI0117 | A test sits in a file that goes to the world | [TsukimiTest] is written in the world-bound file. A test that calls Assert or Mimic keeps that call in the program included in the world, so Unity stops the build and inspect also reports an error (compiles: false). A test that calls neither goes into the program included in the world and is exposed as an entry point (that one is a warning and it compiles). Move the tests to the Name.Tests.cs file |
TUKI0202 | A null comparison that always gives the same result | Comparing a value type against null. It compiles (it doesn’t halt) |
TUKI0203 | Taking a value type out of an object | Reading it costs one conversion. It compiles (it doesn’t halt) |
TUKI0204 | The cost of a 2D array | It turns into boxing each element on the way in and out. It compiles (it doesn’t halt) |
TUKI0116 | A reserved name | Names beginning with __, and the names of the slots that receive the arguments of an event you handle (onPlayerJoinedPlayer for OnPlayerJoined), are used by the compiler for its own heap variables. Renaming the field fixes it |
TUKI0120 | A model that cannot be compiled in | A model named in a model attribute cannot be compiled in. The message says which case it is: the attribute is not written as expected (fix the C# code), the model file cannot be read, or the model contains something that cannot be converted (change the part of the model that the message names; the C# code is not at fault) (ONNX models (experimental)) |
TUKI0121 | A name a shader cannot hold | A name in the part that runs on the GPU (kernels, the methods they call, and their parameters and locals) contains something other than ASCII letters, digits and underscores. Renaming it fixes it (methods and fields that stay on the Udon side can use any name). The error that follows on the Gpu.Run line (or a similar line) that uses that kernel has the same number. That one needs no change of its own: it goes away once the name is fixed |
TUKI0122 | A method with an event’s name that is not an event | A method with the name of a built-in event is not written the way the event is declared (the parameter types, the number of parameters or the return type differ, an event that takes parameters is written without them, or a VRChat event is written without override). It compiles as an ordinary method and is never called as the event. The warning message names the form to write (Events). If it is not meant to be the event, renaming it removes the warning. It is also reported for an Awake that takes no parameters. VRChat does not call Awake, so move its body into Start (it is not reported when the source uses the name Awake anywhere). Compilation succeeds (it does not stop) |
TUKI0123 | Reduced-size weights kept in 16 bits | The layer that reads a trained model’s 8-bit or 4-bit weights cannot use them at that size, so they were kept as 16-bit values. One appears per layer, naming the layer, why it cannot use them, and how many times the memory the weights take. The values computed do not change. To keep the memory down, change how that layer’s weights are quantized, or the shape of the layer, as the reason describes (ONNX models on the GPU (experimental)). Compilation succeeds (it does not stop) |
TUKI0135 | A layer that can go past the 16-bit limit | A model that keeps the values between layers as 16-bit floats (a floating-point model, for example) has a layer that can produce values above 65504, the largest 16-bit value. Such a value is held as 65504 (or -65504 when negative), and differs from the original model. Whether it happens depends on the values given to the model, so the message names the layers, the reason, and how large the input has to get (layers with the same reason share one warning). If the values reaching the named layers stay below the size given, nothing needs to change. To check, compare the output in Unity with the original model’s output on the same input. To stay below the limit, bound that layer’s input inside the model with a Clip, or, where the operation allows, divide by a constant before the layer and multiply back after it (ONNX models on the GPU (experimental)). It compiles (it doesn’t halt) |
TUKI0124 | Instruction count and heap use could not be measured | Instruction count and heap use are measured on the program Unity compiles. Unity leaves Name.Tests.cs files out when it compiles, so when the file passed is itself such a test file, no program is left to measure. It is also reported when the program without those files gives an error in the check Unity runs before it saves the program. The message says which case it is. It appears only when cost is given to inspect. Pass the file that declares the Behaviour (the one whose name does not end in .Tests.cs) (Testing). Compilation succeeds (it does not stop) |
TUKI0125 | File-scoped namespace | namespace X; is C# 10 syntax. Unity also compiles as C# 9, so the same file is an error in Unity as well. Change it to namespace X { and add a } at the end of the file (the code inside does not need to be re-indented) (File layout and namespaces) |
TUKI0126 | A symbol that is not decided outside Unity | An #if or #elif reads a symbol whose definition is not decided outside Unity (one decided by the build target, such as UNITY_ANDROID, or one the file does not #define). The symbol was compiled as undefined. In Unity, the build target and the project’s Scripting Define Symbols decide it, so a different branch can be compiled there (COMPILER_UDONSHARP and UDONSHARP are always defined, and UNITY_EDITOR is never defined). If the branch compiled is the one you meant, nothing has to change. To check the other branch, write #define at the top of the file only while you check (Preprocessor). Compilation succeeds (it does not stop) |
TUKI0127 | A static field that is not shared between instances | A static field of a Behaviour that is not readonly (and a static auto-property with a set) holds a separate value in each instance of the Behaviour. It is not shared the way a C# static is. It is not reported for const or static readonly. If a value per instance is what you want, removing static removes the warning. To share one value, put it in an ordinary field of one Behaviour, and have the other Behaviours read and write it through a reference to that Behaviour set in the Inspector (moving it to a static class does not share it either: reading a static field of a static class that is not readonly is an error) (Member declarations). Compilation succeeds (it does not stop) |
TUKI0128 | Syntax from C# 10 or later | Collection expressions, primary constructors, record struct and global using are syntax from C# 10 or later. Unity also compiles as C# 9, so the same file is an error in Unity as well. The message names the syntax and what to write instead in C# 9 (new int[] { 1, 2, 3 } for [1, 2, 3]). For a primary constructor or a record struct, the other errors in the file do not appear until it is fixed, so compile again after fixing it |
TUKI0129 | A call to a frame-spanning method whose return value is discarded | A call to an async FrameTask method is written as a statement on its own, and the FrameTask it returns is discarded. A call made while every concurrent run (1 by default) is in use does not start, and the only way to know is Started on the returned value. Inside an async FrameTask method, wait for it with await (a method with 2 or more concurrent runs, and a method of another Behaviour, cannot be awaited). Anywhere, Started can be read, as in if (!M().Started) { ... }. If the call may fail to start, write _ = M(); and the warning does not appear (async / await). Compilation succeeds (it does not stop) |
TUKI0130 | The size of the synced values | Information that inspect reports once for each Behaviour that has synced variables. It gives the number of synced variables (a variable of a struct type counts once per field) and the sum of the sizes of the types of the variables whose size does not depend on the value (4 for int and float, 12 for Vector3). A string, a VRCUrl or an array is not in the sum, and is named separately. The sum is not the number of bytes VRChat sends over the network, and it is not compared with any limit. Nothing has to change (Sync). Compilation succeeds (it does not stop) |
TUKI0131 | An initializer on a synced field whose value is not decided | A field with [UdonSynced], or a field that is the target of [FieldChangeCallback], has an initializer whose value cannot be decided at compile time (such as Random.Range(1f, 2f)). An initializer whose value is decided becomes the field’s initial value and is not run at run time. An initializer whose value is not decided runs once, when an event or a public method of that Behaviour is first called, so it overwrites a value received or set from outside before then. Write it in a form whose value is decided, such as a constant, new Vector3(0f, 2f, 0f) or Vector3.up * 2f, or remove the initializer. If a value is needed after removing it, write the code so that it works whichever of OnDeserialization and Start runs first (Sync) |
TUKI0132 | An editor method that Unity never calls | A Behaviour declares OnValidate, OnDrawGizmos or OnDrawGizmosSelected. Unity calls these in the editor on a MonoBehaviour, but a Behaviour written here becomes an Udon program that an UdonBehaviour runs, so Unity never calls them and the code in them does not run. The method compiles as an ordinary method. Move code needed only in the editor into an editor script, and code that runs in the world into an event such as Start. If the method is not meant to be called by Unity, renaming it removes the warning. Compilation succeeds (it does not stop) |
TUKI0111 | Change propagation can’t be built | The reactive attribute was read, but not one piece of change-propagating code could be placed. The effects of that class aren’t run automatically. It appears for a [Reactive] of a type that cannot be compared (an array, DataList, DataDictionary and the like) and for a [Reactive] struct with a member of such a type, and the message names the field or member (Reactive programming) |
TUKI0113 | An effect that nothing runs | The effect’s trigger doesn’t change in any entry point. It compiles (it doesn’t halt) |
TUKI0115 | An attribute on a synced field | A value that arrives doesn’t run the effect (propagation is inserted only in the entry point that writes the value). Give the field a [FieldChangeCallback] whose setter assigns the field, and an arriving value goes through the setter, the effect runs, and this warning is not given. It compiles (it doesn’t halt) |
TUKI0119 | An effect that does not run again when a value it reads changes | An [Effect] (or an effect that reads a [Computed]) is not run again when a value it reads changes. The message says which case it is: no entry point that writes its dependencies is found, so it runs once at startup only; it reads a [Reactive] or [Computed] value of another instance or another class; or an [Effect] with names reads a value it does not name (Reactive programming). It compiles (it doesn’t halt) |
TUKI0134 | A write to a reactive field where its effects do not run | A [Reactive] field is assigned from another class, assigned on another instance of the same class, or written by name with SetProgramVariable (also when the class writes its own field that way). Effects run only when a method of the class that declares the field assigns its own field, so the value changes and the effects do not run. Write a method in that class that assigns the field, and call it from outside. A write by name to a field that also has [FieldChangeCallback] goes through the setter and runs the effects, so it does not get this number (Reactive programming) |
TUKI0235 | A synced array that starts as null | A [UdonSynced] array starts as null. It is reported for an array with no initializer that is not shown in the Inspector (one that is private or [NonSerialized]), and for an array whose initializer is null or default. VRChat’s official documentation says that a Behaviour is not synced while any of its synced arrays is null, so not only that array but none of the other synced variables reach the other players. Give it an initializer such as = new int[0], or assign an array to it before the values are first sent (in Start, for example). Assigning null to it later stops the syncing until an array is assigned again (Sync). It compiles (it doesn’t halt) |
TUKI0255 | A value of another type written by name | SetProgramVariable with the name written out writes a value whose type differs from the field’s type (SetProgramVariable("speed", 2) on a float field, for example). A write by name assigns the value without converting it to the field’s type, so the float field holds an int, and the Behaviour halts where the field is used as a float (in C# the value is converted). Pass a value of the field’s type, such as 2f, or, for your own field, assign it directly. It is reported when the name is decided at compile time (a string literal, a const or nameof) and the target is this Behaviour or a variable whose type is a Behaviour class you declared. A call that passes the name in a variable, a target of type UdonBehaviour, and a value first assigned to an object variable are not checked (Getting and calling components). It does not compile |
TUKI0440 | An event in a test file | An Udon event (an override such as Interact, or a method that VRChat calls by its name, such as Start or Update) is written in a test file (Name.Tests.cs). That file is not included in the world, so the program in the world does not have the event and it is never called. The error is reported when the tests are run (from the Tsukimi Tests window and from the MCP test tool) and when the test file is also passed to inspect, and the tests are not run (a compile for the world does not report it). Move the event into the class’s own file, the one whose name does not end in .Tests.cs. Both files are the same class through partial, so the tests can still call it. Test methods, and the methods and fields the tests use, can stay in the test file (Testing) |
TUKI0485 | A partial file that another program asset points at | Another program asset uses, as its source, one of the files of a Behaviour split with partial. A class is compiled into one program, so that file is left out of this program, and the members in it (Interact, for example) are missing from the program in the world. It is reported when Unity compiles, and neither program asset’s program is compiled. Keep the program asset of the file that declares the base class, and delete the program asset that points at the other file. Keep the file itself (it continues the class and goes into the remaining program) (Quick start) |
TUKI0486 | A Behaviour declared only in a test file | A Behaviour is declared only in a test file (Name.Tests.cs), as in public class LampSuite : TsukimiBehaviour. That file is not included in the world, so the Behaviour is not in the world. The error is reported when the tests are run (from the Tsukimi Tests window and from the MCP test tool) and when that file is passed to inspect, and the tests are not run (a compile for the world does not report it). Declare the Behaviour in its own file whose name does not end in .Tests.cs (LampSuite.cs) and give it a program asset, and keep the tests in LampSuite.Tests.cs as a partial class that does not name the base class (Testing) |
TUKI0490 | Code whose GPU result can differ from C# | A GPU kernel uses a function, an operator or a way of writing a branch whose result on the GPU differs from C# for some values (% on float, Mathf.Pow, Mathf.Log with a base, and assigning one of two compared values before an if and the other inside an if with no else, as in float m = 0f; if (f > 0f) m = f;, among others). It is information that inspect reports: one entry for each kernel and each such function, operator or way of writing, at the first place it is used. The kernel is translated as written. The message says what was used where, and for which values the result differs. When those values cannot reach it, nothing has to change. When they can and the result has to match C#, write it the way the message suggests (take the remainder on int values, or write both values in one place, as in f > 0f ? f : 0f, for example) (Functions callable from a kernel). It compiles (it doesn’t halt) |
TUKI0901 | An internal compiler error | Not a mistake in the code you wrote. The same code may well be correct, so rewriting it won’t necessarily fix it |
TUKI0902 | Analysis failed | The analysis failed partway through. An empty result doesn’t mean the risk is absent |
TUKI0903 | A call in the output program to a name that doesn’t exist | The compiled program calls a name that isn’t in this runtime’s Udon API. The name doesn’t appear in the code you wrote |