naptha/tesseract.js · error · Error
[${id}]: You need to have at least one worker before adding
Error message
[${id}]: You need to have at least one worker before adding jobs What it means
A scheduler routes queued jobs to its pool of workers via dequeue(). addJob guards with getNumWorkers() (Object.keys(workers).length) because a job pushed with no workers would never dispatch. The throw is synchronous inside the async addJob, so it rejects the returned promise immediately.
Source
Thrown at src/createScheduler.js:63
}
});
log(`[${id}]: Add ${job.id} to JobQueue`);
log(`[${id}]: JobQueue length=${jobQueue.length}`);
dequeue();
})
);
const addWorker = (w) => {
workers[w.id] = w;
log(`[${id}]: Add ${w.id}`);
log(`[${id}]: Number of workers=${getNumWorkers()}`);
dequeue();
return w.id;
};
const addJob = async (action, ...payload) => {
if (getNumWorkers() === 0) {
throw Error(`[${id}]: You need to have at least one worker before adding jobs`);
}
return queue(action, payload);
};
const terminate = async () => {
Object.keys(workers).forEach(async (wid) => {
await workers[wid].terminate();
});
jobQueue = [];
};
return {
addWorker,
addJob,
terminate,
getQueueLen,
getNumWorkers,
};View on GitHub (pinned to a1ca80d9e3)
Solutions
- Await createWorker(...) to resolve before calling scheduler.addWorker(worker) and only then call scheduler.addJob(...).
- Guard with scheduler.getNumWorkers() > 0 before addJob, and spawn a worker if zero.
- Ensure workers are added once at startup (e.g. a pool of N workers) rather than per-request.
Example fix
// before
const scheduler = createScheduler();
createWorker('eng').then((w) => scheduler.addWorker(w)); // not awaited
scheduler.addJob('recognize', img); // throws: worker not added yet
// after
const scheduler = createScheduler();
const worker = await createWorker('eng');
scheduler.addWorker(worker);
await scheduler.addJob('recognize', img); Defensive patterns
Strategy: validation
Validate before calling
if (scheduler.getNumWorkers() === 0) {
const w = await createWorker('eng');
scheduler.addWorker(w);
}
await scheduler.addJob('recognize', image); Try / catch
try {
await scheduler.addJob('recognize', image);
} catch (e) {
if (/at least one worker/i.test(e.message)) {
scheduler.addWorker(await createWorker('eng'));
await scheduler.addJob('recognize', image);
} else { throw e; }
} Prevention
- Always await createWorker and call addWorker in the same synchronous block before any addJob.
- Build the worker pool once at application startup and reuse the scheduler.
- Wrap addJob in a helper that lazily spawns a worker when getNumWorkers() === 0.
When it happens
Trigger: Calling scheduler.addJob('recognize', image) before any scheduler.addWorker(worker). Most commonly a race: createWorker(...) is async and the caller invokes addJob before the worker promise resolves and is passed to addWorker.
Common situations: Forgetting to spawn workers; awaiting createWorker in parallel with addJob; refactoring that removes the addWorker step; calling addJob on a fresh scheduler created by createScheduler().
AI-assisted analysis of naptha/tesseract.js@a1ca80d9e3 (2026-08-13).
Data as JSON: /api/errors/dd2ce95091e3a180.
Report an issue: GitHub.