BabylonJS/Babylon.js · error

runTask is not implemented

Error message

runTask is not implemented

What it means

This is the abstract base-class implementation of AbstractAssetTask.runTask. The library throws it when a task is run that never overrode runTask, i.e. a custom or built-in task class forgot to implement the actual loading logic. AssetsManager calls runTask for each task when the AssetsManager.load()/processAsync runs.

Source

Thrown at packages/dev/core/src/Misc/assetsManager.ts:134

            scene,
            () => {
                this._onDoneCallback(onSuccess, onError);
            },
            (msg, exception) => {
                this._onErrorCallback(onError, msg, exception);
            }
        );
    }

    /**
     * Execute the current task
     * @param scene defines the scene where you want your assets to be loaded
     * @param onSuccess is a callback called when the task is successfully executed
     * @param onError is a callback called if an error occurs
     */
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
        throw new Error("runTask is not implemented");
    }

    /**
     * Reset will set the task state back to INIT, so the next load call of the assets manager will execute this task again.
     * This can be used with failed tasks that have the reason for failure fixed.
     */
    public reset() {
        this._taskState = AssetTaskState.INIT;
    }

    private _onErrorCallback(onError: (message?: string, exception?: any) => void, message?: string, exception?: any) {
        this._taskState = AssetTaskState.ERROR;

        this._errorObject = {
            message: message,
            exception: exception,
        };

View on GitHub (pinned to 0592b347b8)

Solutions

  1. Create a subclass and override runTask(scene, onSuccess, onError), calling onSuccess() on success or onError(message, exception) on failure
  2. If you meant to use a built-in loader, instantiate the concrete task type (e.g. TextFileAssetTask, ImageAssetTask) instead of the abstract base
  3. Check the override signature matches exactly: public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void)

Example fix

// before
class MyTask extends AbstractAssetTask {
  // no runTask override
}
// after
class MyTask extends AbstractAssetTask {
  public runTask(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
    try {
      this._data = doLoad();
      onSuccess();
    } catch (e) {
      onError('load failed', e);
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

if (typeof (task as any).runTask !== 'function' || task.constructor === AbstractAssetTask) {
  throw new TypeError('Task must be a concrete subclass that overrides runTask');
}

Type guard

function hasRunTask(t: AbstractAssetTask): t is AbstractAssetTask & { runTask(scene: Scene, onSuccess: () => void, onError: (m?: string, e?: any) => void): void } {
  return t.runTask !== AbstractAssetTask.prototype.runTask;
}

Try / catch

try {
  assetsManager.load();
} catch (e) {
  if (e instanceof Error && e.message === 'runTask is not implemented') {
    console.error('Task class does not override runTask:', e);
  }
}

Prevention

When it happens

Trigger: Calling AssetsManager.load()/run() with a task instance whose class does not override runTask — e.g. instantiating AbstractAssetTask (or a base task) directly, or a custom task subclass that overrides only onSuccess/onError but not runTask.

Common situations: Writing a custom asset task and forgetting to override runTask; refactoring that renamed the override so it no longer matches the signature; using a very old task class from a version whose runTask was renamed.

Related errors


AI-assisted analysis of BabylonJS/Babylon.js@0592b347b8 (2026-08-30). Data as JSON: /api/errors/f69f25f5f36a4848. Report an issue: GitHub.