Summary
Importing a skinned glTF whose mesh nodes all reference the same skin produces ONE Skeletal Mesh in UE 5.7.4 and THREE separate Skeletal Meshes in UE 5.8. Same file, same stock “Assets” pipeline preset, blank project each time.
The cause is not in engine code. The two shipped glTF pipeline content assets store CombineSkeletalMeshesBehavior = DoNotCombine, overriding the C++ class default of BySkeleton:
Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultGLTFAssetsPipeline.uasset
Engine/Plugins/Interchange/Runtime/Content/Pipelines/DefaultGLTFSceneAssetsPipeline.uasset
They are the only shipped presets that override it. No release from 5.3 through 5.7 did, and the same asset is byte-identical on ue5-main, so this is not fixed upstream either.
Workaround: in the import dialog, set Skeletal Meshes > Combine Skeletal Meshes to “Combine All That Use Same Skeleton”.
What Type of Bug are you experiencing?
UI / Tools
Steps to Reproduce
-
Install UE 5.7.4 and UE 5.8 (any 5.8.x - verified on both 5.8.0 and 5.8.1).
-
Obtain a skinned .glb whose mesh nodes all reference the same glTF skin. My repro file has 3 mesh nodes (Body, Face, Hair), all with skin=0, a single skin with 103 joints, and exactly one topmost joint. A minimal repro is pasted as text in Additional Notes so you do not need my file.
-
In UE 5.7.4, create a blank project. Drag the .glb into the Content Browser, press “Use Pipeline Default” in the import dialog, then Import.
Result: one Skeletal Mesh named after the file, plus one Skeleton and one PhysicsAsset. -
In UE 5.8, create a blank project. Import the same .glb the same way, again pressing “Use Pipeline Default”.
Result: THREE Skeletal Meshes named after the glTF nodes (Body, Face, Hair), three PhysicsAssets, and one shared Skeleton. -
To confirm the cause, in the 5.8 import dialog open the “Skeletal Meshes” category and read the “Combine Skeletal Meshes” dropdown. It reads “Do Not Combine Skeletal Meshes”, even though the C++ class default for CombineSkeletalMeshesBehavior is BySkeleton.
-
Set that dropdown to “Combine All That Use Same Skeleton” and re-import. One Skeletal Mesh comes out, matching 5.7.4.
Expected Result
One Skeletal Mesh, as in UE 5.7.4 and every release back to 5.3.
The setting introduced in 5.8, EInterchangeCombineSkeletalMeshesBehavior, declares BySkeleton as its C++ class default, and that value’s own tooltip reads “Combine all the meshes that use a specific Skeleton as a single Skeletal Mesh”. With one skin and one skeleton root, all three meshes should be combined.
Every other shipped pipeline preset - DefaultAssetsPipeline, DefaultFBXOBJAssetsPipeline, DefaultSceneAssetsPipeline - leaves the property at BySkeleton, so glTF should behave the same way.
Observed Result
Three Skeletal Meshes under a single Skeleton, because the two shipped glTF presets override the property to DoNotCombine.
Triangle counts show this is purely a grouping change, with nothing lost or duplicated:
UE 5.7.4 test-1 29,542 tris = glTF mesh 0 + 1 + 2 (13,210 + 7,122 + 9,210)
UE 5.8 Body 13,210 tris = glTF mesh 0 exactly
UE 5.8 Face 7,122 tris = glTF mesh 1
UE 5.8 Hair 9,210 tris = glTF mesh 2
An A/B import that changes only that one property confirms it - same file, same project, same pipeline stack:
A stock DefaultGLTFAssetsPipeline (DoNotCombine) → 3 SkeletalMesh, 1 Skeleton, 3 PhysicsAsset, 20,493 verts total
B same preset, only BySkeleton set → 1 SkeletalMesh, 1 Skeleton, 1 PhysicsAsset, 20,493 verts
Identical vertex totals, so the geometry itself is fine.
Opening Body on its own shows a headless, hairless body, because Face and Hair are now separate assets. In practice a character that used to arrive as one skinned asset now arrives as three that have to be reassembled by hand, and any Blueprint, animation asset, physics asset or retarget setup authored against the 5.7.4 asset no longer matches.
Affects Versions
5.8
Platform(s)
Windows
Upload an image
Additional Notes
Reading the value yourself - no source build needed
Against a stock Epic Games Launcher install:
UnrealEditor-Cmd.exe .uproject -ExecutePythonScript=“probe.py” -unattended -nosplash -nopause -nullrhi -stdout
import unreal
for path in (“/Interchange/Pipelines/DefaultGLTFAssetsPipeline”,
“/Interchange/Pipelines/DefaultGLTFSceneAssetsPipeline”,
“/Interchange/Pipelines/DefaultAssetsPipeline”,
“/Interchange/Pipelines/DefaultFBXOBJAssetsPipeline”,
“/Interchange/Pipelines/DefaultSceneAssetsPipeline”):
mesh = unreal.load_asset(path).get_editor_property(“mesh_pipeline”)
unreal.log(“%s → %s” % (path, mesh.get_editor_property(“combine_skeletal_meshes_behavior”)))
The property is on the pipeline’s MeshPipeline sub-object, not on UInterchangeGenericAssetsPipeline itself. On 5.8 this prints DoNotCombine for the two glTF presets and BySkeleton for the other three, and BySkeleton for the class default object.
The property is visible and unlocked in the glTF import dialog (locked=False, import visible=True in its PropertiesStates), which is why the workaround exists.
When it appeared
These presets are not in the GitHub source tree - they come down through Engine/Build/Commit.gitdeps.xml - so I pulled each release’s copy out of the dependency CDN and hashed it. SHA-1 of DefaultGLTFAssetsPipeline.uasset:
5.4 5f9b8fa658fd29398d28127ed0ac0c3b890e1611 no override
5.5 61261de472989c0f622f4521c3c180f44761bf6a no override
5.6 c8fa8dec2674d9f34567715202d3efb36e36a699 no override
5.7 60c853e84eef3139914e09fac095f34fe0b61064 no override
5.8 55b9a897b3cf741dea7ebfda65e9b1ea1c4da638 DoNotCombine
ue5-main 55b9a897b3cf741dea7ebfda65e9b1ea1c4da638 identical file
DefaultGLTFSceneAssetsPipeline.uasset follows the same pattern and is likewise identical between 5.8 and ue5-main (62f14f18d55800a46ef66603f2c7cbde2d2c541f).
bCombineSkeletalMeshes defaulted to true in 5.3 and 5.4 and was deprecated-but-still-true in 5.5 through 5.7, so glTF skinned meshes sharing a skeleton were combined for five releases. What the glTF presets did carry all along was a property state hiding and locking that bool in the dialog - presumably the “glTF Combine Skeletal Meshes option is gone” reports from the 5.5 era. In 5.8 the option became visible again, and its stored value was flipped at the same time.
The source file cannot justify a split
Parsed straight from the .glb JSON chunk, no Unreal involved:
nodes 129, meshes 3, skins 1
scene root node[128] ‘Armature’
± node[125] ‘Body’ mesh=0 skin=0 (no local transform)
± node[126] ‘Face’ mesh=1 skin=0 (no local transform)
± node[127] ‘Hair’ mesh=2 skin=0 (no local transform)
± node[124] ‘Root’ ← joints[0]; all 103 joints sit under this
skin[0] name=‘Armature’ joints=103 skeleton=
Applying Unreal’s own rule for skeleton roots - a joint whose parent is not itself a joint - gives exactly one root, and 5.8 does create only one Skeleton, so skeleton resolution is working. In Blender there is one Armature at location 0,0,0, rotation identity, scale 1,1,1. No negative-determinant transform anywhere.
Source pipeline: VRoid Studio 2.12.0 → VRM → Blender 5.1.2 → Khronos glTF Blender I/O v5.1.20.
Environment detail
Affected UE 5.8.1 5.8.1-56057345+++UE5+Release-5.8 Epic Games Launcher build
Affected UE 5.8.0 5.8.0-55116800+++UE5+Release-5.8 second machine, different Windows 11 install
Affected ue5-main @ 6eba53a (2026-08-03) same asset, byte-identical
Working UE 5.7.4 5.7.4-51494982+++UE5+Release-5.7
Import path: Interchange, stock Assets pipeline stack (InterchangeGenericAssetsPipeline + InterchangeGLTFPipeline), “Use Pipeline Default” pressed.
Suggested fix
Clear the override on both DefaultGLTFAssetsPipeline and DefaultGLTFSceneAssetsPipeline so they inherit BySkeleton from the class default, matching every other shipped preset - on ue5-main, and as a 5.8.x hotfix.
If splitting really is intended for glTF, it should be in the release notes, and the two glTF presets should at least agree with DefaultSceneAssetsPipeline, which does not split.
A separate, smaller code observation
5.8 turned both combine booleans into enums but only handled one of them. bCombineStaticMeshes_DEPRECATED was kept, with an upgrade in UInterchangeGenericMeshPipeline::PostLoad() that maps the old true onto the new enum. bCombineSkeletalMeshes was deleted outright - no _DEPRECATED member, no [CoreRedirects] entry in DefaultInterchange.ini, and nothing in PostLoad. Grepping Engine/Plugins/Interchange on ue5-main for it returns nothing.
The two were symmetric before 5.8:
bCombineStaticMeshes default false, true meant combine, enum default DoNotCombine, upgrade present
bCombineSkeletalMeshes default true, false meant do not combine, enum default BySkeleton, no upgrade
So a pipeline asset last saved in 5.4 or earlier that explicitly turned skeletal combining off silently gets it back on. That one is in the source tree, so unlike the bug above it can go through a pull request, and I have one prepared.
Repro file
test-1.glb, 12,829,116 bytes, sha256 d93d2f9a451693437146927beec211c81d03d22f0e7ed5cdc12a2a0e20d84146
{
“asset”: {
“version”: “2.0”,
“generator”: “minimal repro for UE 5.8 glTF skeletal mesh split”
},
“scene”: 0,
“scenes”: [
{
“nodes”: [
0
]
}
],
“nodes”: [
{
“name”: “Armature”,
“children”: [
1,
3,
4
]
},
{
“name”: “Root”,
“children”: [
2
]
},
{
“name”: “Bone_01”,
“translation”: [
0,
1,
0
]
},
{
“name”: “MeshA”,
“mesh”: 0,
“skin”: 0
},
{
“name”: “MeshB”,
“mesh”: 1,
“skin”: 0
}
],
“skins”: [
{
“name”: “Armature”,
“joints”: [
1,
2
],
“inverseBindMatrices”: 10
}
],
“materials”: [
{
“name”: “M_Repro”,
“pbrMetallicRoughness”: {
“baseColorFactor”: [
0.8,
0.8,
0.8,
1.0
],
“metallicFactor”: 0.0
}
}
],
“meshes”: [
{
“name”: “MeshA”,
“primitives”: [
{
“attributes”: {
“POSITION”: 0,
“NORMAL”: 1,
“JOINTS_0”: 2,
“WEIGHTS_0”: 3
},
“indices”: 4,
“material”: 0
}
]
},
{
“name”: “MeshB”,
“primitives”: [
{
“attributes”: {
“POSITION”: 5,
“NORMAL”: 6,
“JOINTS_0”: 7,
“WEIGHTS_0”: 8
},
“indices”: 9,
“material”: 0
}
]
}
],
“accessors”: [
{
“bufferView”: 0,
“componentType”: 5126,
“count”: 4,
“type”: “VEC3”,
“min”: [
-1,
0,
0
],
“max”: [
0,
2,
0
]
},
{
“bufferView”: 1,
“componentType”: 5126,
“count”: 4,
“type”: “VEC3”
},
{
“bufferView”: 3,
“componentType”: 5121,
“count”: 4,
“type”: “VEC4”
},
{
“bufferView”: 2,
“componentType”: 5126,
“count”: 4,
“type”: “VEC4”
},
{
“bufferView”: 4,
“componentType”: 5123,
“count”: 6,
“type”: “SCALAR”
},
{
“bufferView”: 5,
“componentType”: 5126,
“count”: 4,
“type”: “VEC3”,
“min”: [
0,
0,
0
],
“max”: [
1,
2,
0
]
},
{
“bufferView”: 6,
“componentType”: 5126,
“count”: 4,
“type”: “VEC3”
},
{
“bufferView”: 8,
“componentType”: 5121,
“count”: 4,
“type”: “VEC4”
},
{
“bufferView”: 7,
“componentType”: 5126,
“count”: 4,
“type”: “VEC4”
},
{
“bufferView”: 9,
“componentType”: 5123,
“count”: 6,
“type”: “SCALAR”
},
{
“bufferView”: 10,
“componentType”: 5126,
“count”: 2,
“type”: “MAT4”
}
],
“bufferViews”: [
{
“buffer”: 0,
“byteOffset”: 0,
“byteLength”: 48,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 48,
“byteLength”: 48,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 96,
“byteLength”: 64,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 160,
“byteLength”: 16,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 176,
“byteLength”: 12,
“target”: 34963
},
{
“buffer”: 0,
“byteOffset”: 188,
“byteLength”: 48,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 236,
“byteLength”: 48,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 284,
“byteLength”: 64,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 348,
“byteLength”: 16,
“target”: 34962
},
{
“buffer”: 0,
“byteOffset”: 364,
“byteLength”: 12,
“target”: 34963
},
{
“buffer”: 0,
“byteOffset”: 376,
“byteLength”: 128
}
],
“buffers”: [
{
“byteLength”: 504,
“uri”: “data:application/octet-stream;base64,AACAvwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAACAvwAAAEAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAgAAAAIAAwAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAQAAAAEAAAABAAAAAQAAAAAAAQACAAAAAgADAAAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAACAvwAAAAAAAIA/”
}
]
}
Minimal repro, as text
This form has no attachment field for non-image files, so here is a self-contained
minimal repro instead. Save it as minimal-repro.gltf and import it - it is plain JSON
with its 504-byte buffer embedded as a base64 data URI, so there is nothing external
to fetch.
Two quads, one skin, two joints, both mesh nodes on skin 0:
node 0 “Armature” children 1, 3, 4 (not a joint)
node 1 “Root” joint child 2 ← the only topmost joint
node 2 “Bone_01” joint, +1 on Y
node 3 “MeshA” mesh 0, skin 0
node 4 “MeshB” mesh 1, skin 0
skins[0].joints = [1, 2]
Verified on 5.8.0-55116800. With the stock Assets preset this produces TWO Skeletal
Meshes (MeshA 4 verts, MeshB 4 verts, one shared Skeleton, two PhysicsAssets).
Changing only Combine Skeletal Meshes to “Combine All That Use Same Skeleton”
produces ONE Skeletal Mesh of 8 verts. The only warnings either way are the two
“Node [MeshA/MeshB] with a skinned mesh is not root” lines, which 5.7 emits as well.
Full character repro file, for reference: test-1.glb, 12,829,116 bytes,
sha256 d93d2f9a451693437146927beec211c81d03d22f0e7ed5cdc12a2a0e20d84146 - not
attachable here (12 MB, and this form only takes images). The minimal .gltf above
shows the same thing. Happy to supply the original if useful.






