naptha/tesseract.js · error · Error

`worker.detect` requires Legacy model, which was not loaded.

Error message

`worker.detect` requires Legacy model, which was not loaded.

What it means

worker.detect() runs Tesseract's DetectOS, which depends on legacy engine components absent from the LSTM-only core. The guard at src/createWorker.js:179 checks lstmOnlyCore and throws before sending any job to the worker thread. detect() therefore requires a worker built with the full core.

Source

Thrown at src/createWorker.js:179

    startJob(createJob({
      id: jobId,
      action: 'setParameters',
      payload: { params },
    }))
  );

  const recognize = async (image, opts = {}, output = {
    text: true,
  }, jobId) => (
    startJob(createJob({
      id: jobId,
      action: 'recognize',
      payload: { image: await loadImage(image), options: opts, output },
    }))
  );

  const detect = async (image, jobId) => {
    if (lstmOnlyCore) throw Error('`worker.detect` requires Legacy model, which was not loaded.');

    return startJob(createJob({
      id: jobId,
      action: 'detect',
      payload: { image: await loadImage(image) },
    }));
  };

  const terminate = async () => {
    if (worker !== null) {
      /*
      await startJob(createJob({
        id: jobId,
        action: 'terminate',
      }));
      */
      terminateWorker(worker);
      worker = null;

View on GitHub (pinned to a1ca80d9e3)

Solutions

  1. Create the worker with { legacyCore: true, legacyLang: true } so the legacy engine and language data are available.
  2. Create the worker with OEM.TESSERACT_ONLY or OEM.TESSERACT_LSTM_COMBINED, which forces legacy core/lang.
  3. Drop detect() and call recognize() with output.layoutBlocks = true to get layout info from the LSTM engine.

Example fix

// before
const worker = await createWorker('eng'); // LSTM-only
const { data } = await worker.detect(img); // throws

// after
const worker = await createWorker('eng', OEM.TESSERACT_LSTM_COMBINED, { legacyCore: true, legacyLang: true });
const { data } = await worker.detect(img);
Defensive patterns

Strategy: validation

Validate before calling

// Track whether the worker was built with legacy support.
const legacyEnabled = options.legacyCore === true || oem === 0 || oem === 2;
async function safeDetect(worker, image, legacyEnabled) {
  if (!legacyEnabled) {
    throw new Error('detect() needs legacy core; recreate worker with legacyCore:true');
  }
  return worker.detect(image);
}
const r = await safeDetect(worker, image, legacyEnabled);

Type guard

const workerSupportsDetect = (creationOem, options) =>
  creationOem === 0 /* TESSERACT_ONLY */ ||
  creationOem === 2 /* TESSERACT_LSTM_COMBINED */ ||
  options?.legacyCore === true;

Try / catch

try {
  await worker.detect(image);
} catch (e) {
  if (/Legacy model.*not loaded/i.test(e.message)) {
    await worker.terminate();
    worker = await createWorker('eng', 2, { legacyCore: true, legacyLang: true });
    return worker.detect(image);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling worker.detect(image) on a worker created with default options (OEM.LSTM_ONLY, no legacyCore flag).

Common situations: Using defaults and wanting orientation/script detection; copying detect() from docs without reading the legacy-core requirement; wanting OSD on a minimal-size build.

Related errors


AI-assisted analysis of naptha/tesseract.js@a1ca80d9e3 (2026-08-13). Data as JSON: /api/errors/86c0309514e889f6. Report an issue: GitHub.