• RuntimesBugs
  • Index was outside the bounds of the array in MeshGenerator

Problem statement

Hi there,
We have been hitting a very hard to repro issue since we upgraded to Spine 4.1 from 3.8.
It seems related to different things:

  • The animation has to be an UI object
  • Starting an animation on the object on the same frame it is enabled / disabled?
  • And doing of all this inside an async / LateUpdate context?
    Sorry I cannot be more precise on how to get the exception to trigger again.

I did manage to have a breakpoint into the spine code once, and here's how much info as I could get out of it:

In the Spine.Unity.MeshGenerator.BuildMeshWithArrays method

  • totalVertexCount is set to be equal to instruction.rawVertexCount
  • We then enter the slot loop line 827 for (int slotIndex = startSlot; slotIndex < endSlot; slotIndex++) {
  • At some point, it seems like more bones are active than initially expected, because we hit a vbi[] array overflow (sometimes around lines 841-844, sometimes line 922) as vertexIndex gets incremented along the way.

Have been giving this a try for a few weeks to repro in a sandbox, but never managed to trigger this in a simple project. Looks like some very edge case - is this something that you have encountered in the past? Any idea what could be happening?

Our initial idea is that instruction.rawVertexCount has a value of how many vertices the previous animation had (on the previous frame), while the slot loop goes over the slots enabled on the next animation, and it might have more vertices than initially computed.

Any help is appreciated

Runtime information

Spine 4.1
Unity 2021.3.20f1

IndexOutOfRangeException: Index was outside the bounds of the array.
Spine.Unity.MeshGenerator.BuildMeshWithArrays (Spine.Unity.SkeletonRendererInstruction instruction, System.Boolean updateTriangles) (at Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs:922)
Spine.Unity.SkeletonGraphic.UpdateMeshSingleCanvasRenderer (Spine.Unity.SkeletonRendererInstruction currentInstructions) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:731)
Spine.Unity.SkeletonGraphic.UpdateMeshToInstructions () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:688)
Spine.Unity.SkeletonGraphic.Rebuild (UnityEngine.UI.CanvasUpdate update) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:286)
UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/CanvasUpdateRegistry.cs:215)
UnityEngine.Canvas:SendWillRenderCanvases() (at /Users/bokken/build/output/unity/unity/Modules/UI/ScriptBindings/UICanvas.bindings.cs:96)
Related Discussions
...

@jeremie-tmx Sorry to hear you're encountering problems, and thanks for reporting. Which version of the spine-unity 4.1 runtime are you using (name of the unitypackage, also listed in Assets/Spine/version.txt)?

jeremie-tmx It's version 4.1.6

This is not the spine-unity runtimes version. Please share the name of the used unitypackage, or the content of the file Assets/Spine/version.txt.

My bad

Here it is: spine-unity-4.1-2022-12-14.unitypackage

@jeremie-tmx Please note that you're not using the latest spine-unity runtime (2023-04-06), there have been 19 commits on the spine-unity subdirectory since your used version, one of which resolved an IndexOutOfRangeException bug: EsotericSoftware/spine-runtimesbf5d445.

Please have a try whether the latest package resolves your issue, if not please let us know.

Hi @Harald and thanks for getting back to me.

I just updated to the latest version spine-unity-4.1-2023-04-06.unitypackage - the error still occurs.

The commit you mentioned changes an Editor only file and doesn't affect Mesh Generation at all and unfortunately won't have an impact on our issue.

Thanks for your help

@jeremie-tmx Thanks for getting back to us. Sorry to hear that the issue persists. Looking at the commit made it rather obvious that this was not affecting mesh generation, I must have confused it with another commit.

Knowing that you already tried to create a simple reproduction project, could you perhaps create a stripped down version of your larger project, where this issue still occurs? Or could you perhaps log which combination of set skins / attachments and animations leads to the issue and then set these same skins and animations to reproduce the issue?

If there is a bug that reads past the end of vbi, it's likely happening more often than you see because vertexBuffer.Items length can be greater than vertexBuffer.Count. To ensure you see it every time it happens, temporarily modify Mesh Generator to call vertexBuffer.TrimExcess() before any reading from vertexBuffer.

I see MeshGenerator TrimExcess but I don't see anywhere it is called.

@Harald, we have ExposedList TrimExcess but CurveTimeline Shrink. The horror! 🫣

Hi @Harald, unfortunately it is really hard to narrow this down on a project of this scale. It does not seem to affect a specific animation / skin either, it's just a super weird issue, hard to reproduce, but still manages to trigger on thousands of our players with no real idea of what the implications are for them.

@Nate Agreed, the exception happens as it overflows but there's probably cases where the vbi array isn't being completely filled.
I tried to call vertexBuffer.TrimExcess() before a few vertexBuffer readings in the BuildMeshWithArrays method but I am now getting constant errors

Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array
Mesh.colors is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.

    jeremie-tmx I tried to call vertexBuffer.TrimExcess() before a few vertexBuffer readings in the BuildMeshWithArrays method but I am now getting constant errors

    Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array
    Mesh.colors is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.

    @jeremie-tmx Thanks for trying out trimming the arrays. The error message you receive comes from trimming only the vertexBuffer (which is only the position buffer, Unity's nomenclature unfortunately uses Vector3 Mesh.vertices as position array instead of an interleaved { position, uv, color, .. } buffer). You would need to trim the uvBuffer and colorBuffer arrays accordingly as well.

    We are having a look at the issue, if you should find any insights resultimg from with trimming the arrays, we are of course very happy to hear them. 🙂

      Harald Okay makes sense
      I used the TrimExcess() method instead which seems to trim pretty much everything
      I added it before any read of vertexBuffer / uvBuffer / colorBuffer (BuildMeshWithArrays, ScaleVertexData, AddAttachmentTintBlack,FillVertexData, FillLateVertexData, EnsureVertexCapacity)

      Still hitting these whenever we play animations though

      Mesh.vertices is too small. The supplied vertex array has less vertices than are referenced by the triangles array.
      UnityEngine.Mesh:set_vertices (UnityEngine.Vector3[])
      Spine.Unity.MeshGenerator:FillVertexData (UnityEngine.Mesh) (at Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs:1084)
      Spine.Unity.SkeletonRenderer:LateUpdateMesh () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:538)
      Spine.Unity.SkeletonRenderer:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:455)
      Spine.Unity.SkeletonAnimation:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:274)
      
      Mesh.uv is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
      UnityEngine.Mesh:set_uv (UnityEngine.Vector2[])
      Spine.Unity.MeshGenerator:FillVertexData (UnityEngine.Mesh) (at Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs:1085)
      Spine.Unity.SkeletonRenderer:LateUpdateMesh () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:538)
      Spine.Unity.SkeletonRenderer:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:455)
      Spine.Unity.SkeletonAnimation:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:274)
      
      Mesh.colors is out of bounds. The supplied array needs to be the same size as the Mesh.vertices array.
      UnityEngine.Mesh:set_colors32 (UnityEngine.Color32[])
      Spine.Unity.MeshGenerator:FillVertexData (UnityEngine.Mesh) (at Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs:1086)
      Spine.Unity.SkeletonRenderer:LateUpdateMesh () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:538)
      Spine.Unity.SkeletonRenderer:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs:455)
      Spine.Unity.SkeletonAnimation:LateUpdate () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonAnimation.cs:274)

      Thanks for the support

        jeremie-tmx Thanks for your efforts. We have found a potential (and likely) cause where the vertex buffer can have the wrong size: If after SkeletonGraphic.LateUpdate() (where render-instructions are updated) another script modifies any attachments (by setting e.g. skeletonGraphic.Skeleton.SetAttachment() or Skeleton.SetSkin()), and the canvas update CanvasUpdateRegistry.PerformUpdate triggers a SkeletonGraphic.Rebuild(), there is one missing call to update the render-instructions after the modified attachments.

        So after a script modifies the skeleton from LateUpdate(), a call to skeletonGraphic.UpdateMesh() (actually only skeletonGraphic.PrepareInstructionsAndRenderers()) would fix this missing call. We're working on a proper clean bugfix, we hope to have one ready by tomorrow.

        Hi @Harald and thanks for your response. I am glad that you found something, especially since it does seem like our issue seems to be related to a weird chain of events related to a LateUpdate context.

        Didn't have a chance to try your fix in detail yet, if you have a fixed version by that time I will download it and try otherwise I will have a deeper look ASAP. Thanks again 🙂

        @jeremie-tmx We have just released a bugfix for the above issue on both 4.1 and 4.2-beta branches.

        Details: Now an automatic additional update (PrepareInstructionsAndRenderers) is performed when skeletonGraphic.Skeleton is accessed after SkeletonGraphic (which may potentially change active attachments at slots).

        New spine-unity unitypackages are available for download here as usual:
        https://esotericsoftware.com/spine-unity-download
        Please let us know if the above update resolves the issue on your end as well. Thanks for reporting!

        This issue has been tracked under this issue ticket:
        EsotericSoftware/spine-runtimes2275

        6 days later

        @Harald Thanks for the update
        Unfortunately the issue remains using spine-unity-4.1-2023-04-13.unitypackage

        IndexOutOfRangeException: Index was outside the bounds of the array.
        Spine.Unity.MeshGenerator.BuildMeshWithArrays (Spine.Unity.SkeletonRendererInstruction instruction, System.Boolean updateTriangles) (at Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs:841)
        Spine.Unity.SkeletonGraphic.UpdateMeshSingleCanvasRenderer (Spine.Unity.SkeletonRendererInstruction currentInstructions) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:775)
        Spine.Unity.SkeletonGraphic.UpdateMeshToInstructions () (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:732)
        Spine.Unity.SkeletonGraphic.Rebuild (UnityEngine.UI.CanvasUpdate update) (at Assets/Spine/Runtime/spine-unity/Components/SkeletonGraphic.cs:314)
        UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/CanvasUpdateRegistry.cs:215)
        UnityEngine.Canvas:SendWillRenderCanvases() (at /Users/bokken/build/output/unity/unity/Modules/UI/ScriptBindings/UICanvas.bindings.cs:96)

        At some point I will give it another go to sandbox this scenario. In the meantime if you have any other lead as to what might be happening I'd be happy to hear them.

        Thanks again for your support!

        @jeremie-tmx Oh dear, very sorry to hear that your issue still persists!

        Could you perhaps have a look at whether somewhere in your script code in LateUpdate() (or in any other event method hook which is issued after LateUpdate()) you are perhaps directly accessing and modifying parts of the skeleton, like changing attachments at cached slots, and the like? This would unfortunately bypass the logic that detects any modification to the skeleton which only monitors the skeletonGraphic.Skeleton getter property.

          a year later

          Harald
          Hi, I have had my eyes on this post for a while now, but noticed someone else posted about this error log here (https://esotericsoftware.com/forum/d/25724-fatal-exception-indexoutofrangeexception), so I'm following up here to say that I've been encountering a similar issue too.

          I am not quite sure where the bug is coming from, but I can give some details:

          • It only happens in builds (not in Editor)
          • On our end, it only happens when we first load up our environment (a town). Every town has a bunch of NPCs (30+) using SkeletonAnimation, and a couple of menus that each have one or more character SPINEs (SkeletonGraphic), but the error only pops up for four NPCs when loading up one specific town (initializing all SPINEs). I can't figure out which ones are throwing the error (at least based from the log).
          • The game doesn't crash or break as a result, and from what I've seen, the NPCs look fine.
          • However, these four errors pop up every time during play and messes with our error tracking.

          Some thoughts from me:

          • Could this be as easy as going through all of the NPCs in the town, resetting the SPINE (whatever default assets/materials are set already), building, and testing it again?
          • Based on the stack trace, the LateUpdate() from Unity's ScrollRect is triggering this error, but only four times... so there has to be some kind of mismatch or issue with timing.
          • Again, it's only in one town, and because this is a SkeletonGraphic issue, I assume that there's a menu in the town that is causing an issue when first initiated... I'll keep taking a look and will keep you updated, but please let me know if there's anything else I can do to find out the issue for this (and why it seemingly only happens in builds!)

          Here's the full stack trace ⤵️

          Uploading Crash Report
          IndexOutOfRangeException: Index was outside the bounds of the array.
            at Spine.Unity.MeshGenerator.BuildMeshWithArrays (Spine.Unity.SkeletonRendererInstruction instruction, System.Boolean updateTriangles) [0x00bb8] in <6dd7f65da0cb495b8b298cec8c065fc6>:0 
            at Spine.Unity.SkeletonGraphic.UpdateMeshSingleCanvasRenderer (Spine.Unity.SkeletonRendererInstruction currentInstructions) [0x0006a] in <6dd7f65da0cb495b8b298cec8c065fc6>:0 
            at Spine.Unity.SkeletonGraphic.UpdateMeshToInstructions () [0x00040] in <6dd7f65da0cb495b8b298cec8c065fc6>:0 
            at Spine.Unity.SkeletonGraphic.Rebuild (UnityEngine.UI.CanvasUpdate update) [0x00035] in <6dd7f65da0cb495b8b298cec8c065fc6>:0 
            at UnityEngine.UI.CanvasUpdateRegistry.PerformUpdate () [0x0015b] in <8feb70aa6437467687fee8eb58d4b3e7>:0 
          UnityEngine.DebugLogHandler:Internal_LogException(Exception, Object)
          UnityEngine.DebugLogHandler:LogException(Exception, Object)
          Sentry.Unity.Integrations.UnityLogHandlerIntegration:LogException(Exception, Object)
          UnityEngine.Logger:LogException(Exception, Object)
          UnityEngine.Debug:LogException(Exception, Object)
          UnityEngine.UI.CanvasUpdateRegistry:PerformUpdate()
          UnityEngine.Canvas:SendWillRenderCanvases()
          UnityEngine.Canvas:ForceUpdateCanvases()
          UnityEngine.UI.ScrollRect:EnsureLayoutHasRebuilt()
          UnityEngine.UI.ScrollRect:LateUpdate()

          Regards,
          Julian

            @JulianRice Sorry to hear you're facing this issue as well, thanks for your detailed writeup. Unfortunately the stack trace where the exception happens is already known, the question is which call modifies the skeleton's state before SkeletonGraphic.Rebuild is called. As mentioned above in previous postings, if user code modifies visible attachments after SkeletonGraphic.LateUpdate() but before SkeletonGraphic.Rebuild(), things could go out of sync. However, we've already added an automatic check when accessing SkeletonGraphic.Skeleton between these calls and trigger a second update automatically to re-sync SkeletonGraphic to the modification. Modifying the skeleton through a cached Skeleton skeleton = SkeletonGraphic.Skeleton however would bypass this safety check and explain the exception. Are you performing any modification of active skins or visible attachments from LateUpdate() in your scripts? If so, could you please share your exact code? If you're uncertain, you could perhaps add breakpoints in Skeleton.SetSkin and Slot.Attachment.set, or if that's not catching anything: add Debug.Log statements in said methods to see if any SetSkin or Attachment.set call at runtime lies between LateUpdate and Rebuild.

            JulianRice Could this be as easy as going through all of the NPCs in the town, resetting the SPINE (whatever default assets/materials are set already), building, and testing it again?

            I'm not sure if I understood this sentence correctly. If you mean that you could create a minimal Unity project by reducing the number of skeletons until only the problematic skeleton is left which still causes the issue in the built executable: that would be great! If you could provide us with such a minimal reproduction project, please send it to contact@esotericsoftware.com, briefly mentioning this forum thread URL so that we know the context. Then we can have a look at what's going wrong.

            JulianRice Based on the stack trace, the LateUpdate() from Unity's ScrollRect is triggering this error, but only four times... so there has to be some kind of mismatch or issue with timing.

            The issue occurs only when more attachment vertices are required (and written to) than are available. When things get out of sync the first time, an out-of-bounds exception will be raised, but when activating the same or a similar skin later, the vertex buffers likely have already been enlarged to sufficient size to cover the new skin, even if it's a different set of attachments now.

            JulianRice I'll keep taking a look and will keep you updated, but please let me know if there's anything else I can do to find out the issue for this (and why it seemingly only happens in builds!)

            Thanks very much for your offer! We are currently performing some more investigations on our side, but would be very happy if you could see if you could perhaps create a minimal reproduction project as described above, of check whether any calls that change the skin or attachments happen.

            @JulianRice @jeremie-tmx We have just pushed a commit to both 4.1 and 4.2-beta branches which should fix the issue. New unitypackages are available for download here as usual:
            https://esotericsoftware.com/spine-unity-download

            Details: The commit reverts the structural change of distributing the UpdateMesh procedure into LateUpdate and Rebuild which introduced the possibility for modifying the skeleton attachment state at the wrong time.

            Issue ticket URL for later reference:
            EsotericSoftware/spine-runtimes2487