EmbedPDF

Errors & cancelling

Every call that fails rejects with an EngineError. Its code says what went wrong, so you can handle each case:

import { EngineError, EngineErrorCode } from '@embedpdf/engine';
 
try {
  await page.annotations.update(ref, { contents: 'Done' });
} catch (error) {
  if (EngineError.is(error, EngineErrorCode.Forbidden)) {
    showMessage('You can only edit your own comments.');
  } else if (EngineError.is(error, EngineErrorCode.NotFound)) {
    showMessage('This comment was deleted.');
  } else {
    throw error;
  }
}

EngineError.is(error, code) checks both that it’s an engine error and that it has that code. Branch on the code, never on the message: messages are for people and can change.

Cancelling a call#

Every call returns a promise you can cancel. Keep it, and call abort() when you no longer need the answer:

const rendering = page.render.image({ viewport: { kind: 'width', width: 1600 } });
 
// The user scrolled past the page:
rendering.abort();

The promise rejects right away with code Aborted, and the engine stops the work if it hasn’t finished. Cancelling a call that already finished does nothing.

try {
  const image = await rendering;
} catch (error) {
  if (EngineError.is(error, EngineErrorCode.Aborted)) return; // we cancelled it
  throw error;
}

Only the promise the call returned has abort(): rendering.then(…) gives a plain promise. Keep the original.

A time limit is a cancel on a timer:

const listing = doc.annotations.list();
const timer = setTimeout(() => listing.abort(), 5000);
 
try {
  return await listing;
} finally {
  clearTimeout(timer);
}

When the rest of your code cancels with an AbortController (a fetch, a framework’s cleanup), tie the call to its signal with abortWith():

const controller = new AbortController();
 
const image = await page.render.image().abortWith(controller.signal);
 
// later, in your cleanup:
controller.abort();

The call is cancelled when the signal aborts, or at once if it already has.

Error codes#

The codes you’ll handle most:

CodeWhat happened
ForbiddenThe user doesn’t have the permission. error.details.required names it.
NotFoundThe page, annotation or field isn’t there (anymore).
InvalidArgSomething you passed isn’t valid. The message says what.
AbortedYou cancelled the call.
DocPasswordRequiredThe file needs a password. See Opening documents.
DocPasswordIncorrectunlock() got a wrong password.
DocOpenFailedThe file isn’t a PDF, or is too damaged to open.
PayloadTooLargeAn import or export is past a limit. error.details has the limit and max.
ProtectedDocumentA signature in the document forbids this change.
ObjectNumberUnavailableA create named an object number this session doesn’t hold, or used one twice.
ChangeConflictA change’s expect didn’t match the document. Nothing was written. See Changes & undo.
UndoUnavailableThe change can’t be undone anymore. error.details.reason says why: 'final-change' or 'expired'.
LayerFullThe document has as many objects as a PDF file should; a compacted copy starts afresh.

Good to know#

Every code#

CodeWhat happened
DocNotOpenThe document was closed.
RuntimeUnavailableThe engine was destroyed, or the browser lacks something it needs.
MalformedPdfThe file opened, but part of it is too damaged to use.
NotImplementedThis engine can’t do this (yet).
SigningPendingA signature is being made; finish or cancel it first.
SigningExpiredThe signature took too long; start it again.
SigningVersionMismatchThe document changed while the signature was being made; start it again.
SignatureRefusedThis field can’t be signed. The message says why.
StaleBaseThe document was signed elsewhere; this copy can be edited but not signed.
IdempotencyKeyReusedAn opId that already named another change was used again.
WireFormatThe server sent something the engine didn’t expect.
UnknownAnything else. Please report it.

details#

Some errors carry more in error.details: the missing permission for Forbidden, the field for InvalidArg, the limit for PayloadTooLarge. Log error.toJSON() to see everything an error has.

Was this page helpful?

Your feedback goes directly to the documentation team.