{"record":{"id":"56280710c847bd0a","repo":"pixijs/pixijs","slug":"endbundle-called-without-an-active-render-bundle","errorCode":null,"errorMessage":"endBundle called without an active render bundle.","messagePattern":"endBundle called without an active render bundle\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/rendering/renderers/gpu/GpuEncoderSystem.ts","lineNumber":156,"sourceCode":"        // A bundle encoder exposes the same render/bind command API as the pass, so it stands in as\n        // the write target while recording. The real pass stays in _passEncoder and is restored by\n        // endBundle.\n        this.renderPassEncoder = this._gpu.device.createRenderBundleEncoder(descriptor);\n    }\n\n    /**\n     * Finishes recording the current render bundle and restores the previous render pass encoder.\n     * @returns The recorded {@link GPURenderBundle} ready to be executed via {@link executeBundle}.\n     */\n    public endBundle(): GPURenderBundle\n    {\n        const encoder = this.renderPassEncoder;\n\n        // `finish` only exists on a bundle encoder, so it both narrows the type for the call below\n        // and guards against endBundle being called without an active bundle.\n        if (!encoder || !('finish' in encoder))\n        {\n            throw new Error('endBundle called without an active render bundle.');\n        }\n\n        const bundle = encoder.finish();\n\n        this.renderPassEncoder = this._passEncoder;\n        this._clearCache();\n\n        return bundle;\n    }\n\n    /**\n     * Replays a previously recorded render bundle on the current render pass.\n     * The bound state cache is cleared since the bundle may set its own pipeline, bind groups, and buffers.\n     * @param bundle - The render bundle to execute.\n     */\n    public executeBundle(bundle: GPURenderBundle): void\n    {\n        this._clearCache();","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/pixijs/pixijs/blob/4b141e3ced7255b39c2114b6bca03421a37b2363/src/rendering/renderers/gpu/GpuEncoderSystem.ts#L138-L174","documentation":"Thrown by GpuEncoderSystem.endBundle() when no render bundle is currently being recorded. The check looks for a non-null renderPassEncoder that has a 'finish' method (only bundle encoders have finish). A null renderPassEncoder or a real pass encoder (no finish) means there is nothing to end, so the call is rejected.","triggerScenarios":"Calling endBundle() without a prior successful beginBundle(), or after endBundle() has already been called once (double-end). Also when the render pass itself has ended, leaving renderPassEncoder null.","commonSituations":"Unbalanced begin/end calls. Calling endBundle in a cleanup/finalize path that runs even when recording never started. A previous endBundle already restored the pass encoder.","solutions":["Track your own recording flag and only call endBundle when it is true.","Ensure every endBundle corresponds to exactly one preceding successful beginBundle.","Reset your flag in a finally block so a second cleanup pass does not call endBundle again."],"exampleFix":"// before\nlet bundle = encoder.endBundle(); // throws if no bundle active\n\n// after\nlet recording = false;\nencoder.beginBundle();\nrecording = true;\ntry {\n  recordDraws();\n} finally {\n  if (recording) { bundle = encoder.endBundle(); recording = false; }\n}","handlingStrategy":"validation","validationCode":"let recording = false;\nencoder.beginBundle(); recording = true;\n// ... record ...\nif (recording) { encoder.endBundle(); recording = false; }","typeGuard":"function hasActiveBundle(encoder: GpuEncoderSystem): boolean {\n  return !!encoder.renderPassEncoder && 'finish' in encoder.renderPassEncoder;\n}","tryCatchPattern":null,"preventionTips":["Pair every beginBundle with exactly one endBundle via a flag.","Reset the flag in finally so cleanup paths don't double-end.","Never call endBundle from a generic finalize routine without checking state."],"tags":["webgpu","encoder","render-bundle","state-machine","lifecycle"],"backgroundTag":null,"analyzedSha":"4b141e3ced7255b39c2114b6bca03421a37b2363","analyzedAt":"2026-08-12T17:27:29.507Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}