Inspect events and runs

Trace a failed run back to its event and step so you can fix the cause.

Trace a failed workflow from its trigger event to the run and failed step. This shows what completed before you choose a recovery action.

Inspect an event

  1. Select the environment in the dashboard and open Events.
  2. Filter by time or open an event type to narrow the list.
  3. Open the event to inspect its payload and the functions it triggered.
  4. Use Show search for a CEL query such as event.data.orderId == "123" when you know a payload field.

Inspect a run

  1. Open Runs in the selected environment to see runs across all apps. Filter by status, queued or started time, or app. To see one function's runs, open it from Functions.
  2. Search for a known event field or output, for example output.name == "NonRetriableError".
  3. Open the run. Check its trigger, input, output, timing, and step timeline.
  4. Expand a failed step to see each retry's error and timing.

The run details show three things:

  • Trigger details: the run and trigger IDs. Share these when you contact support.
  • Event payload: the event that triggered the run.
  • Run details: the run's status, error, and a timeline of its steps. Open it in a new tab for a full-page view, which helps with runs that have many steps or retries.

The run's error tells you what failed. The timeline tells you where: find the failed step, then expand it to see whether every retry raised the same error or the failure was temporary.

Search runs

Select Show search next to the run filters and enter a CEL expression. Run search supports the event and output variables and basic operators:

FieldTypeOperators
event.idstring==, !=
event.namestring==, !=
event.tsint64==, !=, >, >=, <, <=
event.vstring==, !=
event.datamap[string]any==, !=, >, >=, <, <=
outputany==, !=, >, >=, <, <=

For example, event.data.hello == "world" or output.success != true.

Combine queries with && or ||. A new line works the same as &&.

Search for errors

A failed run stores its error as JSON on output. When the SDK supports it, the error has structured fields. For example, this TypeScript error:

throw new NonRetriableError("Failed to import data");

is stored as:

{
  "name": "NonRetriableError",
  "message": "Failed to import data",
  "stack": "NonRetriableError: Failed to import data\n    at ..."
}

and matches this search:

output.name == "NonRetriableError" && output.message == "Failed to import data"

Custom error classes make failures easier to find by type:

import { NonRetriableError } from "inngest";

class UserNotFoundError extends NonRetriableError {
  constructor(message: string) {
    super(message);
    this.name = "UserNotFoundError";
  }
}

inngest.createFunction(
  { id: "my-fn", triggers: { event: "user" } },
  async ({ step, event }) => {
    await step.run("get-user", async () => {
      const user = await getUser(event.data.userId);
      if (!user) {
        throw new UserNotFoundError(`User not found (${event.data.userId})`);
      }
    });
  }
);
event.data.userId == "12345" && output.name == "UserNotFoundError"

Reproduce or recover

  • Reproduce locally: send the trigger event to your local Dev Server. This reproduces failures that depend on the input rather than on external factors such as a recent deploy or bad data.
  • Rerun: if the failure was temporary or you've deployed a fix, select Rerun. You can also select a step in the trace to rerun from that step. See Rerun a run.

Before any recovery action, identify which side effects completed. A rerun or replay can execute them again.