{"record":{"id":"a0f2619078acac89","repo":"FyroxEngine/Fyrox","slug":"gltf-unable-to-extract-blend-shape-names-from-jso","errorCode":null,"errorMessage":"glTF: Unable to extract blend shape names from JSON: {}","messagePattern":"glTF: Unable to extract blend shape names from JSON: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fyrox-impl/src/resource/gltf/mod.rs","lineNumber":539,"sourceCode":"            json::Value::Object(map) => {\n                if let Some(names) = map.get(TARGET_NAMES_KEY) {\n                    match names {\n                        json::Value::Array(names) => {\n                            values_to_strings(names.as_slice()).unwrap_or_default()\n                        }\n                        _ => Vec::default(),\n                    }\n                } else {\n                    Vec::default()\n                }\n            }\n            _ => Vec::default(),\n        }\n    } else {\n        Vec::default()\n    };\n    if extras.is_some() && names.is_empty() {\n        Log::warn(format!(\n            \"glTF: Unable to extract blend shape names from JSON: {}\",\n            extras.as_ref().unwrap().get()\n        ));\n    }\n    Ok(BlendShapeInfoContainer::new(names, weights))\n}\n\nfn values_to_strings(values: &[json::Value]) -> Option<Vec<String>> {\n    let mut result: Vec<String> = Vec::with_capacity(values.len());\n    for v in values {\n        if let json::Value::String(str) = v {\n            result.push(str.clone());\n        } else {\n            return None;\n        }\n    }\n    Some(result)\n}","sourceCodeStart":521,"sourceCodeEnd":557,"githubUrl":"https://github.com/FyroxEngine/Fyrox/blob/76c91aad8eca488ce527b1af707be8b3b24ad72d/fyrox-impl/src/resource/gltf/mod.rs#L521-L557","documentation":"glTF import reads blend shape (morph target) names from the mesh extras JSON. If extras exist but no names could be parsed out of the JSON, the importer warns with the raw JSON content and returns an empty name list, so blend shapes will have no names.","triggerScenarios":"import_morph_info encountering a glTF mesh whose extras contain blend shape data (e.g. targetNames) but in a malformed or unexpected JSON shape so the names array comes back empty.","commonSituations":"Exporter writing targetNames in a non-standard location or format (e.g. not a JSON string array); hand-edited glTF files; tools emitting extras the importer doesn't recognize.","solutions":["Ensure mesh extras contain a valid targetNames array of strings (e.g. {\"targetNames\":[\"smile\",\"frown\"]})","Re-export the glTF from a tool that writes standard morph target names","Fix or remove the malformed extras JSON in the .gltf/.glb"],"exampleFix":"// before (glTF extras)\n\"extras\": { \"targetnames\": \"smile frown\" }\n// after\n\"extras\": { \"targetNames\": [\"smile\", \"frown\"] }","handlingStrategy":"validation","validationCode":"// validate extras JSON before import\nif let Some(extras) = &mesh.extras {\n    let names: Option<Vec<String>> = serde_json::from_str::<serde_json::Value>(extras.get())\n        .ok().and_then(|v| v.get(\"targetNames\").and_then(|n| serde_json::from_value(n.clone()).ok()));\n    if extras.get() != \"null\" && names.map_or(true, |n| n.is_empty()) {\n        eprintln!(\"glTF extras lacks valid targetNames: {}\", extras.get());\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Ensure exporters write targetNames as a JSON string array in mesh extras","Validate glTF extras JSON during asset pipeline checks","Name morph targets in the DCC before export"],"tags":["gltf","blend-shapes","json","import"],"backgroundTag":"json-parse-error","analyzedSha":"76c91aad8eca488ce527b1af707be8b3b24ad72d","analyzedAt":"2026-09-10T16:04:01.633Z","contentChangedAt":"2026-09-10T16:04:01.633Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}