Sume scheduled run returned skipped: detect previous_run_active

A Sume scheduled run that overlaps another returns 200 with status skipped, not an error. Check skip_reason in code, and choose reject if a drop must be loud.

4 min readSume
All posts

A skipped scheduled run is a success response. When a run is already active and on_active_run is skip, which is the default for scheduled runs, Sume returns 200 with a receipt whose status is skipped and whose skip_reason is previous_run_active. If your code only checks for a 2xx, you will treat a dropped trigger as a launched one (Sume docs: Trigger a schedule by API, read 2026-10-06).

Check the status field, not just the HTTP code, and decide whether a skip is acceptable for that job.

What the two policies return

With skip, the API records a run row and answers 200. With reject, it records no run and answers 409 action_run_in_progress. The same 200 is also used for an idempotency replay, so a 200 can mean either 'this was skipped' or 'I have seen this key before'. The receipt tells you which: a replay carries idempotency_hit true, a skip carries status skipped.

Use skip when overlap is expected and harmless, such as a frequent refresh where the next tick will catch up. Use reject when a dropped trigger must surface as an error in your caller, such as a once-a-day report you promised to a person.

Handle all three outcomes

The script below fires a trigger and branches on the three results. Keep the Idempotency-Key between 1 and 255 characters, and derive it from the business event, like the date, so a retry replays rather than duplicates.

import os, requests

H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"],
     "Idempotency-Key": "weekly-recap-2026-10-06"}
url = "https://api.sume.com/v1/actions/acme/weekly-recap/runs"
r = requests.post(url, json={"on_active_run": "reject"},
                  headers=H, timeout=30)
if r.status_code == 409:
    print("previous run still active: alert a human")
elif r.status_code in (200, 202):
    d = r.json()["data"]
    if d.get("status") == "skipped":
        print("skipped:", d.get("skip_reason"))
    elif d.get("idempotency_hit"):
        print("replay of an earlier run")
    else:
        print("started", d["id"])
else:
    print(r.status_code, r.text[:200])

Why runs overlap in the first place

Overlap usually means a run is slower than its interval, or a manual trigger landed on top of a scheduled one. Read the receipt of the run that is holding the slot before you blame the trigger. If runs routinely outlast the interval, lengthen the interval rather than relying on skips to hide the problem.

Scheduled runs are read at /v1/action-runs/{id} and carry their own statuses (queued, processing, completed, failed, canceled, skipped), so build your monitoring around the receipt route.

Outcomes of a schedule trigger, read 2026-10-06 against Sume docs
SituationHTTPSignal in body
Started202status queued
Skipped, skip policy200status skipped, skip_reason previous_run_active
Rejected, reject policy409error action_run_in_progress
Idempotency replay200idempotency_hit true

Alert on repeated skips

One skip is noise. Three in a row is a pattern. Count consecutive skipped receipts per schedule and alert when the count passes a threshold you choose. That turns a silent failure mode into a visible one without making every overlap an error.

Choosing the policy per schedule

There is no single right answer for on_active_run. A refresh that runs every few minutes should skip, because the next one will cover it. A promised daily deliverable should reject, because a skipped run means a missed delivery and you want to know. Write the choice and the reason next to each trigger in your code.

Remember that the default for Format runs is allow, which lets overlapping runs both proceed, and that bulk queue items always run with allow. Skip and reject are specific to schedule triggers and single run calls where you set them.

Sources

Related posts

More in Agents

All Agents posts

Written by Sume