mrdoob/three.js · error · Error

THREE.Renderer: .hasCompatibility() called before the backen

Error message

THREE.Renderer: .hasCompatibility() called before the backend is initialized. Use "await renderer.init();" before using this method.

What it means

Thrown by Renderer.hasCompatibility() when the backend is not yet initialized. Like hasFeature(), this queries the live backend, which only exists after renderer.init() resolves. Calling it earlier has no backend to answer the query.

Source

Thrown at src/renderers/common/Renderer.js:3835

		this._currentSourceMaterial = previousSourceMaterial;

		//

		object.onAfterRender( this, scene, camera, geometry, material, group );

	}

	/**
	 * Checks if the given compatibility is supported by the selected backend.
	 *
	 * @param {string} name - The compatibility's name.
	 * @return {boolean} Whether the compatibility is supported or not.
	 */
	hasCompatibility( name ) {

		if ( this._initialized === false ) {

			throw new Error( 'THREE.Renderer: .hasCompatibility() called before the backend is initialized. Use "await renderer.init();" before using this method.' );

		}

		return this.backend.hasCompatibility( name );

	}

	/**
	 * This method represents the default `_handleObjectFunction` implementation which creates
	 * a render object from the given data and performs the draw command with the selected backend.
	 *
	 * @private
	 * @param {Object3D} object - The 3D object.
	 * @param {Material} material - The object's material.
	 * @param {Scene} scene - The scene the 3D object belongs to.
	 * @param {Camera} camera - The camera the object should be rendered with.
	 * @param {LightsNode} lightsNode - The current lights node.
	 * @param {?{start: number, count: number}} group - Only relevant for objects using multiple materials. This represents a group entry from the respective `BufferGeometry`.

View on GitHub (pinned to da05705fa3)

Solutions

  1. Call `await renderer.init();` before `renderer.hasCompatibility(name);`.
  2. Move the compatibility check into the post-init phase of your app bootstrap.
  3. Use renderer.hasInitialized() to gate the call and defer if not yet ready.

Example fix

// before
const renderer = new WebGPURenderer();
const compat = renderer.hasCompatibility('storage-buffer'); // throws

// after
const renderer = new WebGPURenderer();
await renderer.init();
const compat = renderer.hasCompatibility('storage-buffer');
Defensive patterns

Strategy: validation

Validate before calling

async function safeHasCompatibility(renderer, name) {
  if (!renderer.hasInitialized()) await renderer.init();
  return renderer.hasCompatibility(name);
}

Type guard

function rendererReady(renderer) {
  return typeof renderer.hasInitialized === 'function' && renderer.hasInitialized();
}

Try / catch

try {
  return renderer.hasCompatibility(name);
} catch (e) {
  if (/hasCompatibility\(\) called before/.test(e.message)) { await renderer.init(); return renderer.hasCompatibility(name); }
  else throw e;
}

Prevention

When it happens

Trigger: Calling renderer.hasCompatibility(name) on a renderer constructed but not yet initialized, e.g. to decide whether to enable a compatibility-mode code path at startup.

Common situations: Capability checks run at module load or in a constructor. Code that branches between WebGL and WebGPU compatibility paths before the first render. Migrations that previously had synchronous backend init.

Related errors


AI-assisted analysis of mrdoob/three.js@da05705fa3 (2026-08-12). Data as JSON: /api/errors/1d23e10e8985acce. Report an issue: GitHub.