Collecting Errors 4.0.0+

Introduction

Errors from the tasks are collected inside an array in the main listr task list as tasks.err where tasks is the listr class. Since there are options to ignore some errors on cases like exitOnError or the ability to retry the given task through task.retry, encountered errors can be swallowed while the execution. To deal with those swallowed errors, all the errors that are encountered even though it does not stops the execution gets collected through this property.

Modes

This is related to the discussions on issue #615: "Add Option to Disable Error Collection".


Thanks BeeeQueue for bringing this up!

Error collection now has three modes to choose from which are, false, minimal and full. This can be set through per task in the listr options with the key collectErrors.

Due to potential memory leaks from cloning the context and task to the ListrError, default mode is minimal, which will only collect where the error has occurred, when it has been encountered and what the error.message is.

If you want to fetch the full information for debugging you can set the mode to full. This will also clone the current context and task to the ListrError.

You can disable the error collection completely by setting it to false.

ListrError

ListrError class has some additional information like the cause of the error and where it is coming from and the frozen context at the given time to further debug the issue while execution.

Constructors

constructor

new ListrError<Ctx>(error, type, task)

Type parameters
NameType
Ctxextends Record<PropertyKey, any> = Record<PropertyKey, any>
Parameters
NameType
errorError
typeListrErrorTypes
taskListrTaskObject<Ctx, typeof ListrRenderer>
Overrides

Error.constructor

Defined in

src/interfaces/listr-error.interface.ts:10

ListrErrorTypes

A listr error can be caused by multiple reasons, for a better explanation of why that particular error occurred, a type property on the ListrError exists.

Enumeration members

WILL_RETRY

WILL_RETRY = "WILL_RETRY"

Task has failed and will try to retry.

Defined in

src/interfaces/listr-error.interface.ts:32


WILL_ROLLBACK

WILL_ROLLBACK = "WILL_ROLLBACK"

Task has failed and will try to rollback.

Defined in

src/interfaces/listr-error.interface.ts:34


HAS_FAILED_TO_ROLLBACK

HAS_FAILED_TO_ROLLBACK = "HAS_FAILED_TO_ROLLBACK"

Task has failed, ran the rollback action but the rollback action itself has failed.

Defined in

src/interfaces/listr-error.interface.ts:36


HAS_FAILED

HAS_FAILED = "HAS_FAILED"

Task has failed.

Defined in

src/interfaces/listr-error.interface.ts:38


HAS_FAILED_WITHOUT_ERROR

HAS_FAILED_WITHOUT_ERROR = "HAS_FAILED_WITHOUT_ERROR"

Task has failed, but exitOnError is set to false, so will ignore this error.

Defined in

src/interfaces/listr-error.interface.ts:40

Usage

The order of the array tasks.err where tasks is the listr class, represents the order of errors that are encountered.

To keep the error collection mechanism simple and predictable, it might also process the errors coming from the subtasks as well.

For example, the following example will clear some things up about the given mindset.

const task = new Listr(
  [
    {
      task: (): void => {
        throw new Error('1')
      }
    },
    {
      task: (_, task): Listr => {
        return task.newListr(
          [
            {
              task: (): void => {
                throw new Error('3')
              }
            },
            {
              task: (): void => {
                throw new Error('4')
              }
            }
          ],
          { exitOnError: true }
        )
      }
    },
    {
      task: (): void => {
        throw new Error('2')
      }
    }
  ],
  { exitOnError: false }
)
  • Tasks are concurrent, so we expect them to run in a synchronous fashion.
  • First error will be thrown from the first task. Since exitOnError is false on that context, ListrError will get collected by tasks.err and the value will be { message: '1', type: ListrErrorTypes.HAS_FAILED_WITHOUT_ERROR }.
  • Then it will recurse into the second task which has two subtasks.
  • The first task from the subtasks will fail and since the exitOnError is set to true in that context, that subtasks will fail and throw. The ListrError appended to the tasks.err will be { message: '3', type: ListrErrorTypes.HAS_FAILED }
  • Since the subtask has crashed, it will not execute the upcoming tasks in the subtasks.
  • It will return to the main task list and execute the 3rd task from that list. It will again show the same behavior with the first task and the ListrError will be { message: '2', type: ListrErrorTypes.HAS_FAILED_WITHOUT_ERROR }.
Edit this page on GitHub Updated at Tue, Feb 1, 2022