mrdoob/three.js · error · Error
THREE.Renderer: .hasFeature() called before the backend is i
Error message
THREE.Renderer: .hasFeature() called before the backend is initialized. Use "await renderer.init();" before using this method.
What it means
Thrown by Renderer.hasFeature() when the renderer's backend has not yet been initialized. The WebGPU/WebGL backend (adapter, device, GL context) is created lazily during renderer.init(), which is async; calling hasFeature() before that point has no backend to query. The library throws rather than silently returning false so callers fail loudly on a missing await.
Source
Thrown at src/renderers/common/Renderer.js:3041
if ( this._initialized === false ) await this.init();
return this.backend.resolveTimestampsAsync( type );
}
/**
* Checks if the given feature is supported by the selected backend. If the
* renderer has not been initialized, this method always returns `false`.
*
* @param {string} name - The feature's name.
* @return {boolean} Whether the feature is supported or not.
*/
hasFeature( name ) {
if ( this._initialized === false ) {
throw new Error( 'THREE.Renderer: .hasFeature() called before the backend is initialized. Use "await renderer.init();" before using this method.' );
}
return this.backend.hasFeature( name );
}
/**
* Returns `true` when the renderer has been initialized.
*
* @return {boolean} Whether the renderer has been initialized or not.
*/
hasInitialized() {
return this._initialized;
}
View on GitHub (pinned to da05705fa3)
Solutions
- Add `await renderer.init();` immediately after constructing the renderer, before any hasFeature/initTexture/render call.
- Use the deprecated async wrapper `await renderer.hasFeatureAsync(name)` which inits internally (will emit a deprecation warning).
- Guard the call with `if (renderer.hasInitialized()) { renderer.hasFeature(name) }` and otherwise defer the check until after init resolves.
- Run your feature check inside the same async scope that renders the first frame, so init has already been triggered by render/compute.
Example fix
// before
const renderer = new WebGPURenderer();
if (renderer.hasFeature('float32-blendable')) { /* ... */ } // throws
// after
const renderer = new WebGPURenderer();
await renderer.init();
if (renderer.hasFeature('float32-blendable')) { /* ... */ } Defensive patterns
Strategy: validation
Validate before calling
async function ensureInit(renderer) {
if (!renderer.hasInitialized()) await renderer.init();
}
// usage:
await ensureInit(renderer);
if (renderer.hasFeature('float32-blendable')) { /* ... */ } Type guard
function canQueryFeatures(renderer) {
return typeof renderer.hasInitialized === 'function' && renderer.hasInitialized() === true;
} Try / catch
try {
if (renderer.hasFeature(name)) { /* path A */ }
} catch (e) {
if (/hasFeature\(\) called before/.test(e.message)) { await renderer.init(); /* retry */ }
else throw e;
} Prevention
- Centralize renderer construction in an async factory that awaits renderer.init() before returning the renderer.
- Always treat `new WebGPURenderer()` as incomplete; pair every construction with an awaited init.
- Grep your codebase for `.hasFeature(` and ensure each call site is preceded by an awaited init.
When it happens
Trigger: Calling renderer.hasFeature('float32-blendable') (or any GPUFeatureName) on a freshly constructed WebGPURenderer / Renderer without first awaiting renderer.init(). Common in module-top-level code, app bootstrap, or capability checks done synchronously after `new WebGPURenderer()`.
Common situations: Upgrading from a three.js version where the backend initialized synchronously in the constructor (pre-r181 async-init change). Copying examples that omit `await renderer.init()`. Doing feature detection at the top of a module before the async init promise has resolved.
Related errors
- THREE.Renderer: .initTexture() called before the backend is
- THREE.Renderer: .initRenderTarget() called before the backen
- THREE.Renderer: .hasCompatibility() called before the backen
- THREE.Renderer: .render() called before the backend is initi
- THREE.PMREMGenerator: .fromScene() called before the backend
AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12).
Data as JSON: /api/errors/455426a91511dca5.
Report an issue: GitHub.