Inngest retries a failed step four times: key the Sume submit

Inngest's default is four retries after the first attempt, five in all, and side effects are not exactly-once. Give the Sume submit an Idempotency-Key.

4 min readSume
All posts

A step that submits a paid Sume job can run up to five times, and the Inngest docs say side effects are not guaranteed exactly-once. Send an Idempotency-Key derived from the event data so repeated attempts return one job.

Inngest facts are from its error-handling and Functions docs; Sume facts from Communication modes and Errors and credits, read 2026-10-01.

How many attempts does a step get?

The error-handling docs give the default as four retries after the first attempt, so five attempts in total. They tell you to use idempotency keys for writes, payments and messages, because side effects are not guaranteed exactly-once.

Attempts and Sume outcome, from the Inngest and Sume docs read 2026-10-01
AttemptReaches SumeWith a stable key
1Job created, response lostJob exists
2 to 5Same request againOriginal job returned, one charge
Any, with a different keyRequest againA new paid job each time

Where does the key come from?

From the event, not the step. Use a field that is the same on every attempt, such as an order id plus a revision. Sume treats an exact retry under one key as the same job, and a changed payload under the same key returns 409 idempotency_conflict.

What does the function look like?

The function config shape below follows the current Inngest docs example. Return the job id from the step and do the waiting somewhere else, by webhook or a poll that honors next_poll_after_seconds.

import { createSumeClient, generateVideoV1 } from "@sume-com/sdk";
import { inngest } from "./client";

const client = createSumeClient({ apiKey: process.env.SUME_API_KEY! });

export const makeVideo = inngest.createFunction(
  { id: "make-video", triggers: { event: "shop/video.requested" } },
  async ({ event, step }) => {
    return await step.run("submit-sume-job", async () => {
      const { data, error } = await generateVideoV1({
        client,
        headers: { "idempotency-key": "video-" + event.data.orderId },
        body: { prompt: event.data.prompt, mode: "async" },
      });
      if (error) throw new Error(JSON.stringify(error));
      return data!.data.request_id;
    });
  },
);

Should every error retry?

No. A 400, 401 or 402 fails identically each time; stop those early with the pattern in the NonRetriableError post.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume