{"record":{"id":"325e76aeb3789ec6","repo":"BabylonJS/Babylon.js","slug":"releasetexture-can-t-find-the-texture-in-the-poo","errorCode":null,"errorMessage":"_releaseTexture: Can't find the texture in the pool ${textureOptionsHash}!","messagePattern":"_releaseTexture: Can't find the texture in the pool (.+?)!","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/dev/smartFilters/src/runtime/renderTargetGenerator.ts","lineNumber":170,"sourceCode":"\r\n    private _releaseTexture(texture: ThinTexture, textureOptionsHash: string) {\r\n        if (!this._optimize) {\r\n            return;\r\n        }\r\n\r\n        const refCountedTextures = this._renderTargetPool.get(textureOptionsHash);\r\n        if (!refCountedTextures) {\r\n            throw new Error(`_releaseTexture: Trying to release a texture from a non existing pool ${textureOptionsHash}!`);\r\n        }\r\n\r\n        for (const refCountedTexture of refCountedTextures) {\r\n            if (refCountedTexture.texture === texture) {\r\n                refCountedTexture.refCount--;\r\n                return;\r\n            }\r\n        }\r\n\r\n        throw new Error(`_releaseTexture: Can't find the texture in the pool ${textureOptionsHash}!`);\r\n    }\r\n\r\n    /**\r\n     * Creates an offscreen texture to hold on the result of the block rendering.\r\n     * @param runtime - The current runtime we create the texture for\r\n     * @param smartFilter - The smart filter the texture is created for\r\n     * @param textureOptions - The options to use to create the texture\r\n     * @returns The render target texture\r\n     */\r\n    private _createTexture(runtime: InternalSmartFilterRuntime, smartFilter: SmartFilter, textureOptions: OutputTextureOptions): ThinRenderTargetTexture {\r\n        const engine = runtime.engine;\r\n\r\n        // We are only rendering full screen post process without depth or stencil information\r\n        const setup: RenderTargetCreationOptions = {\r\n            generateDepthBuffer: false,\r\n            generateStencilBuffer: false,\r\n            generateMipMaps: false,\r\n            samplingMode: 2, // Babylon Constants.TEXTURE_LINEAR_LINEAR,\r","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/BabylonJS/Babylon.js/blob/0592b347b8a4ee0236089ea86a749cacfdb266d8/packages/dev/smartFilters/src/runtime/renderTargetGenerator.ts#L152-L188","documentation":"When releasing a render target texture, the pool entry for the textureOptionsHash exists, but none of the ref-counted textures inside it matches the texture being released. The runtime tracks textures by identity within each pool bucket, so this means the texture object was never pooled under that hash (wrong hash, a different texture instance, or the matching entry was already evicted). Like error 860 it only fires when _optimize is on.","triggerScenarios":"_releaseTexture iterates refCountedTextures for the hash and finds no entry whose .texture === the passed texture — caused by passing a texture created with different options (different hash bucket), passing a stale/cloned texture reference, or releasing a texture twice after the first release removed/mutated bookkeeping.","commonSituations":"Caching Babylon.js texture objects across runtime rebuilds, comparing textures by structural equality instead of identity, mixing textures produced by two generators, or framework bugs in the frame-graph release path.","solutions":["Release the exact texture object returned by the generator — never a copy, clone, or re-created texture with the same options.","Verify the textureOptionsHash derivation matches how the texture was originally acquired.","Check for double-release: once a texture is returned to the pool, drop the reference instead of releasing again.","Keep all acquire/release pairs within a single runtime/generator instance lifetime.","If it persists, capture the hash and texture id and report — indicates an internal ref-counting bug."],"exampleFix":"// before\nconst tex = generator.createRenderTargetTexture(options);\ntex.dispose(); // released externally, generator release later fails\n// after\nconst tex = generator.createRenderTargetTexture(options);\n// let the runtime release it: runtime._releaseTexture(hash, tex) exactly once","handlingStrategy":"try-catch","validationCode":"function canRelease(generator, hash, texture) {\n  return (generator._renderTargetPool?.get(hash) ?? []).some((r) => r.texture === texture);\n}","typeGuard":"function textureMatchesPoolEntry(texture, entry) {\n  return entry != null && entry.texture === texture;\n}","tryCatchPattern":"try {\n  generator._releaseTexture(hash, texture);\n} catch (e) {\n  if (String(e.message).startsWith(\"_releaseTexture: Can't find the texture in the pool\")) {\n    console.warn(\"Skipping release of non-pooled texture\", hash);\n  } else { throw e; }\n}","preventionTips":["Always release the identical object reference returned by acquire — no clones.","Verify hash derivation matches the acquire-time options.","Guard against double release with a released-flags set.","Confine acquire/release to one runtime lifetime.","Compare textures by identity, never structural equality."],"tags":["smart-filters","render-target-pool","texture-lifecycle","internal-state"],"backgroundTag":"texture-double-release","analyzedSha":"0592b347b8a4ee0236089ea86a749cacfdb266d8","analyzedAt":"2026-08-30T15:11:20.442Z","schemaVersion":2},"datasetVersion":"2026-08-30T18:17:15.746Z"}