naptha/tesseract.js · critical · Error
${data}
Error message
${data} What it means
When the worker thread rejects a job (status === 'reject'), onMessage rejects the corresponding promise and then either invokes the user-supplied errorHandler or, if none was provided, runs throw Error(data) inside the message-event listener. Because that listener is not an awaited async function, the throw surfaces as an uncaught exception rather than a normal rejection, and the thrown message is just the stringified worker-side error data.
Source
Thrown at src/createWorker.js:217
return Promise.resolve();
};
onMessage(worker, ({
workerId, jobId, status, action, data,
}) => {
const promiseId = `${action}-${jobId}`;
if (status === 'resolve') {
log(`[${workerId}]: Complete ${jobId}`);
promises[promiseId].resolve({ jobId, data });
delete promises[promiseId];
} else if (status === 'reject') {
promises[promiseId].reject(data);
delete promises[promiseId];
if (action === 'load') workerResReject(data);
if (errorHandler) {
errorHandler(data);
} else {
throw Error(data);
}
} else if (status === 'progress') {
logger({ ...data, userJobId: jobId });
}
});
const resolveObj = {
id,
worker,
load,
writeText,
readText,
removeFile,
FS,
reinitialize,
setParameters,
recognize,
detect,View on GitHub (pinned to a1ca80d9e3)
Solutions
- Pass errorHandler: (err) => { /* log/handle */ } in the options to createWorker — this replaces the throw.
- Ensure every awaited worker job has a .catch() so the promise rejection path is handled.
- As a last line of defense, register a process-level uncaughtException listener in Node.js.
Example fix
// before
const worker = await createWorker('eng'); // no errorHandler
await worker.recognize(badImg); // worker rejects -> uncaught throw
// after
const worker = await createWorker('eng', {
errorHandler: (err) => console.error('worker error:', err),
});
try { await worker.recognize(badImg); } catch (e) { /* handled */ } Defensive patterns
Strategy: try-catch
Try / catch
// Always pass an errorHandler so the internal `throw Error(data)` branch is never reached.
const worker = await createWorker('eng', OEM.LSTM_ONLY, {
errorHandler: (err) => {
// log/transport; do NOT rethrow inside the message listener
logger.error('tesseract worker error:', err);
},
});
// AND always await jobs inside try/catch:
try {
const { data } = await worker.recognize(image);
} catch (jobErr) {
// the promise-rejection path; safe to handle/rethrow here
logger.error('recognize failed:', jobErr);
} Prevention
- Always pass an errorHandler in createWorker options; it replaces the uncaught throw.
- Never assume a worker job will resolve — wrap every await in try/catch.
- Register a process-level uncaughtException / window.onerror handler as a safety net.
- Log both the awaited-promise rejection and the errorHandler argument to deduplicate reports.
When it happens
Trigger: Any worker-side job rejection (image decode failure, recognize crash, FS error) when createWorker was called without an errorHandler option. The same rejection is delivered twice: once to the awaited promise, once as the uncaught throw.
Common situations: Default config in Node.js where no errorHandler is set; image/load failures during processing crashing the process; confusing double-reporting of the same error.
AI-assisted analysis of naptha/tesseract.js@a1ca80d9e3 (2026-08-13).
Data as JSON: /api/errors/f530444680836f19.
Report an issue: GitHub.