BabylonJS/Babylon.js · error
updateWrappedNativeTexture: target InternalTexture was not p
Error message
updateWrappedNativeTexture: target InternalTexture was not produced by wrapNativeTexture.
What it means
updateWrappedNativeTexture can only repoint an InternalTexture whose source is InternalTextureSource.External, i.e. one created by wrapNativeTexture. The guard exists because repointing a non-external texture would bypass ownership of its native handle and corrupt engine state.
Source
Thrown at packages/dev/core/src/Engines/thinNativeEngine.pure.ts:2158
* Intended for the device-loss / device-restored flow (a DisableRendering / EnableRendering cycle from the host
* application): when the host recreates its external resource on the new graphics device, it calls this method to
* repoint Babylon's wrapper at the new handle without losing references held by materials, render-target wrappers,
* particle systems, etc.
*
* The new handle must match the wrapped texture's recorded dimensions. To change dimensions, dispose the wrapped
* texture and call {@link wrapNativeTexture} again. Sampling mode and mip-map flag are properties of the logical
* wrapped texture and are re-applied to the new resource. Any render-target wrapper holding this texture as its
* color attachment has its framebuffer rebuilt with the new handle.
*
* Throws if the target was not produced by {@link wrapNativeTexture}, if the new handle's dimensions don't match,
* if the wrapped texture is part of a multi render-target, or if the wrapper has a depth/stencil texture (these
* are not supported in this version; dispose and re-wrap).
* @param internalTexture defines the wrapped InternalTexture to repoint
* @param texture defines the new native texture handle to wrap
*/
public updateWrappedNativeTexture(internalTexture: InternalTexture, texture: NativeTexture): void {
if (internalTexture.source !== InternalTextureSource.External) {
throw new Error("updateWrappedNativeTexture: target InternalTexture was not produced by wrapNativeTexture.");
}
const newWidth = this._engine.getTextureWidth(texture);
const newHeight = this._engine.getTextureHeight(texture);
if (newWidth !== internalTexture.baseWidth || newHeight !== internalTexture.baseHeight) {
throw new Error(
`updateWrappedNativeTexture: new handle dimensions (${newWidth}x${newHeight}) must match the wrapped texture's dimensions (${internalTexture.baseWidth}x${internalTexture.baseHeight}).`
);
}
if (this._engine.getTextureLayerCount) {
const newLayerCount = this._engine.getTextureLayerCount(texture);
const oldLayerCount = internalTexture.is2DArray ? internalTexture.depth : 1;
if (newLayerCount !== oldLayerCount) {
throw new Error(`updateWrappedNativeTexture: new handle layer count (${newLayerCount}) must match the wrapped texture's layer count (${oldLayerCount}).`);
}
}
// Pre-validate before mutating any state so a thrown precondition leaves the InternalTexture untouched.
View on GitHub (pinned to 0592b347b8)
Solutions
- Only pass InternalTextures returned from engine.wrapNativeTexture().
- If you need to swap the underlying data of a regular texture, recreate it (dispose + create) instead.
- Track wrapped textures explicitly (e.g. keep the value returned by wrapNativeTexture) rather than reading texture from a render target.
Example fix
// before engine.updateWrappedNativeTexture(rt.texture, newNativeTex); // rt texture is not wrapped // after const wrapped = engine.wrapNativeTexture(oldNativeTex, width, height, ...); engine.updateWrappedNativeTexture(wrapped, newNativeTex);
Defensive patterns
Strategy: validation
Validate before calling
if (internalTexture.source !== BABYLON.InternalTextureSource.External) {
throw new Error("updateWrappedNativeTexture requires a texture from wrapNativeTexture");
} Type guard
const isWrappedNativeTexture = (t: BABYLON.InternalTexture): boolean => t.source === BABYLON.InternalTextureSource.External;
Try / catch
try {
engine.updateWrappedNativeTexture(tex, newNativeTex);
} catch (e) {
if (e.message.includes("not produced by wrapNativeTexture")) {
console.warn("Recreating texture instead of updating", e);
recreateTexture(tex);
} else throw e;
} Prevention
- Keep wrapNativeTexture return values in dedicated variables/types (e.g. WrappedNativeTexture).
- Never pass render-target textures to updateWrappedNativeTexture.
- Add an assertion helper in your renderer that checks source === External before swaps.
When it happens
Trigger: Calling engine.updateWrappedNativeTexture(internalTexture, nativeTexture) on a texture created via createTexture/createRawTexture or a render-target texture (source !== External).
Common situations: Keeping a plain created texture in a variable that also holds wrapped textures and passing the wrong one; assuming any InternalTexture can be updated.
Related errors
- Unsupported buffer type
- updateWrappedNativeTexture: new handle dimensions (${newWidt
- updateWrappedNativeTexture: new handle layer count (${newLay
- updateWrappedNativeTexture: wrapped texture is part of a mul
- updateWrappedNativeTexture: wrapped texture's render-target
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/2af041b80c9e49e9.
Report an issue: GitHub.