Skip to content

Error recovery

Core reports structured errors; the application decides what the user sees and when an operation should be retried. Retry with the original input after the underlying problem has been resolved—do not reuse internal PDF.js tasks or share retry state between Viewer instances.

NOTE

Display error.message or an application-written message. Keep error.cause for diagnostics only: stringifying it into the UI or telemetry can expose URLs, request headers, credentials, or document data.

Common recovery paths

ScenarioCore resultApplication action
PDF URL, network, or parsing failurePDF_LOAD_FAILEDKeep the original PdfSource and call core.load(source) again.
HTTP Range request failurePDF_RANGE_FAILEDRetry after the server or network recovers. Network failures do not silently become a full download.
Server does not support RangeAutomatic fallback when range: 'auto'; otherwise PDF_RANGE_UNSUPPORTEDUse range: 'auto', or retry with range: false when full download is acceptable.
Incorrect passwordpasswordRequired event with reason: 'incorrect'Keep the same password dialog open and submit another password for the active requestId.
User cancels password inputPending load rejects with PDF_PASSWORD_CANCELLEDReturn to the document picker or let the user start a new load.
Application cancels loadingPending load rejects with PDF_LOAD_CANCELLEDTreat cancellation as expected; start a new load only when requested.
Page, search, thumbnail, or raster operation failsPDF_FEATURE_FAILED, often with operation and pageIndexRetry the specific feature after fixing its input or browser resource problem.
PDF permission blocks printingPDF_PERMISSION_DENIEDDisable printing and explain that the document does not allow it.
Core instance has been destroyedENGINE_DESTROYEDCreate a new instance; a destroyed instance cannot be restarted.

Retry a document load

Keep the source in application state and create a new load attempt from it:

ts
import { InkLayerError } from '@inklayer-dev/core'

const retryButton = document.querySelector<HTMLButtonElement>('#retry')!
const source = { url: '/documents/review.pdf', range: 'auto' as const }

async function openPdf(): Promise<void> {
  retryButton.hidden = true

  try {
    await core.load(source)
  } catch (error) {
    if (error instanceof InkLayerError && error.code === 'PDF_LOAD_FAILED') {
      retryButton.hidden = false
      retryButton.onclick = () => { void openPdf() }
      return
    }

    throw error
  }
}

await openPdf()

Use an application-defined retry limit or backoff policy when repeated network requests would be expensive.

Handle password retries

A wrong password does not start a new PDF load. The current loading task remains active and emits another password request:

ts
const stopPassword = core.viewer.subscribe(event => {
  if (event.type !== 'passwordRequired') return

  openPasswordDialog({
    reason: event.request.reason,
    attempt: event.request.attempt,
    submit(password: string) {
      core.viewer.submitPassword(event.request.requestId, password)
    },
    cancel() {
      core.viewer.cancelPassword(event.request.requestId)
    }
  })
})

Call stopPassword() when the surrounding component or workspace is removed.

Branch on stable fields

InkLayerError provides code, and may also provide operation, annotationId, and a zero-based pageIndex. Branch on these structured fields rather than matching the human-readable message.

Annotation validation and permission failures commonly use ANNOTATION_INVALID; custom type availability uses ANNOTATION_TYPE_UNAVAILABLE; import and export boundaries use IMPORT_FAILED and EXPORT_FAILED. The complete InkLayerErrorCode union is exported from @inklayer-dev/core.

Released under the MIT License.