BabylonJS/Babylon.js · error
updateWrappedNativeTexture: wrapped texture's render-target
Error message
updateWrappedNativeTexture: wrapped texture's render-target wrapper has a depth/stencil texture; not supported. Dispose and re-wrap.
What it means
updateWrappedNativeTexture refuses to update a wrapped texture whose render-target wrapper owns a depth/stencil texture. After a DisableRendering/EnableRendering cycle the bgfx framebuffer and depth/stencil handle become stale, and rebuilding them during the swap is non-trivial, so v1 rejects and asks the caller to dispose and re-wrap.
Source
Thrown at packages/dev/core/src/Engines/thinNativeEngine.pure.ts:2190
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.
// Note: rtWrapper.texture only returns _textures[0]; walk every attachment to catch the multi-RT case where
// the wrapped texture is at index > 0.
for (const rtWrapper of this._renderTargetWrapperCache) {
if (!rtWrapper.textures?.includes(internalTexture)) {
continue;
}
if (rtWrapper.isMulti) {
throw new Error("updateWrappedNativeTexture: wrapped texture is part of a multi render-target; not supported. Dispose and re-wrap.");
}
if (rtWrapper._depthStencilTexture) {
// After a DisableRendering / EnableRendering cycle the bgfx framebuffer + the depth/stencil texture's
// bgfx handle are both stale. Rebuilding the depth/stencil texture from the wrapper's stored settings
// is feasible but non-trivial; v1 rejects and asks the caller to dispose + re-wrap.
throw new Error("updateWrappedNativeTexture: wrapped texture's render-target wrapper has a depth/stencil texture; not supported. Dispose and re-wrap.");
}
}
internalTexture._hardwareTexture = new NativeHardwareTexture(texture, this._engine);
internalTexture.isReady = true;
this.updateTextureSamplingMode(internalTexture.samplingMode, internalTexture);
// Rebuild the framebuffer of any render-target wrapper holding this wrapped texture as its color attachment.
// After a DisableRendering / EnableRendering cycle the bgfx framebuffer handle is stale; the consumer-supplied
// new texture is the moment we have a fresh handle to rebuild against.
for (const rtWrapper of this._renderTargetWrapperCache) {
if (rtWrapper.texture !== internalTexture) {
continue;
}
const nativeRTWrapper = rtWrapper as NativeRenderTargetWrapper;
// NativeRenderTargetWrapper._framebuffer setter releases the old framebuffer before assigning,
// so no manual _releaseFramebufferObjects call is needed (and would double-delete the handle).
nativeRTWrapper._framebuffer = this._engine.createFrameBuffer(
View on GitHub (pinned to 0592b347b8)
Solutions
- Dispose the render-target wrapper (which frees the depth/stencil texture) and recreate it with the new native texture via wrapNativeTexture.
- Create the render target without a depth/stencil attachment if depth is not needed.
- Avoid DisableRendering/EnableRendering cycles around the wrapped RT, or recreate state after such cycles.
Example fix
// before
engine.updateWrappedNativeTexture(rt.texture, newNativeTex); // rt has depth/stencil
// after
rtWrapper.dispose();
rtWrapper = engine.createRenderTargetTexture(size, { ...opts, texture: engine.wrapNativeTexture(newNativeTex, w, h, ...) }); Defensive patterns
Strategy: validation
Validate before calling
const rt = engine._renderTargetWrapperCache.find(rt => rt.textures?.includes(wrapped));
if (rt && rt._depthStencilTexture) throw new Error("RT wrapper has depth/stencil texture; dispose and re-wrap required."); Try / catch
try {
engine.updateWrappedNativeTexture(wrapped, newNativeTex);
} catch (e) {
if (e.message.includes("depth/stencil")) {
rtWrapper.dispose();
rtWrapper = createRTWithWrappedTexture(newNativeTex, depthStencilOpts);
} else throw e;
} Prevention
- Prefer dispose + recreate for render targets that own depth/stencil attachments.
- Create depth-less render targets when hot-swapping color textures is required.
- Be aware DisableRendering/EnableRendering cycles stale bgfx handles; rebuild RTs around them.
When it happens
Trigger: engine.updateWrappedNativeTexture called on a texture whose rtWrapper._depthStencilTexture is set (render target created with a depth/stencil attachment), even if it is not an MRT.
Common situations: Offscreen scene rendering with depth testing where the color texture's native handle is recreated externally (e.g. by a compositor) and the code tries to repoint it.
Related errors
- updateWrappedNativeTexture: wrapped texture is part of a mul
- updateWrappedWebGLTexture: wrapped texture is part of a mult
- updateWrappedNativeTexture: target InternalTexture was not p
- updateWrappedNativeTexture: new handle dimensions (${newWidt
- updateWrappedNativeTexture: new handle layer count (${newLay
AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30).
Data as JSON: /api/errors/6fadcc066b80cdf4.
Report an issue: GitHub.