@browserless/errors
Version:
Enhanced error handling for headless browser automation. Provides detailed, actionable error messages for debugging Puppeteer issues.
92 lines (70 loc) • 2.62 kB
JavaScript
const debug = require('debug-logfmt')('browserless:error')
const { serializeError } = require('serialize-error')
const ensureError = require('ensure-error')
const whoops = require('whoops')
const ERROR_NAME = 'BrowserlessError'
const createErrorFactory = opts => whoops(ERROR_NAME, opts)
const markAsProcessed = error => {
Object.defineProperty(error, '__parsed', {
value: true,
writable: false,
enumerable: false,
configurable: false
})
return error
}
const createBrowserlessError = opts => {
const createError = createErrorFactory(opts)
return (...args) => markAsProcessed(createError(...args))
}
const isObject = value => value !== null && typeof value === 'object'
const browserlessError = {}
browserlessError.browserTimeout = createBrowserlessError({
code: 'EBRWSRTIMEOUT',
message: ({ timeout }) => `Promise timed out after ${timeout} milliseconds`
})
browserlessError.protocolError = createBrowserlessError({ code: 'EPROTOCOL' })
browserlessError.evaluationFailed = createBrowserlessError({
code: 'EINVALEVAL',
message: 'Evaluation failed'
})
browserlessError.contextDisconnected = createBrowserlessError({
code: 'EBRWSRCONTEXTCONNRESET',
message: 'The browser context is not connected.'
})
browserlessError.ensureError = rawError => {
if (isObject(rawError) && rawError.__parsed) return rawError
debug('ensureError', serializeError(rawError))
const error = isObject(rawError) && 'error' in rawError ? rawError.error : rawError
const errorMessage = isObject(error) && typeof error.message === 'string' ? error.message : ''
if (
[
'Protocol error (Target.createTarget): Failed to find browser context with id',
'Protocol error (Target.createTarget): Target closed',
'Protocol error (Target.createBrowserContext): Target closed'
].some(message => errorMessage.startsWith(message))
) {
return browserlessError.contextDisconnected()
}
if (errorMessage.startsWith('Protocol error')) {
return browserlessError.protocolError({
message: errorMessage.split(': ')[1]
})
}
if (
['Evaluation failed', 'Cannot read properties of undefined'].some(message =>
errorMessage.startsWith(message)
) ||
errorMessage.endsWith('is not defined')
) {
const messages = errorMessage.split(': ')
return browserlessError.evaluationFailed({
message: messages[messages.length - 1]
})
}
return ensureError(error)
}
const isBrowserlessError = error => error.name === ERROR_NAME
module.exports = browserlessError
module.exports.isBrowserlessError = isBrowserlessError