A blank Idempotency-Key on Sume is ignored, not rejected: guard it

An empty or whitespace Idempotency-Key header is treated as no key at all, so a retry can create a second job. Build a key that cannot be blank in Python.

4 min readSume
All posts

If a Sume submit goes out with Idempotency-Key: and nothing after it, the API does not return an error. The shared header reader trims the value, and an empty result is read as no key. The request is accepted as an ordinary submit, with no replay protection at all. A retry after a timeout then creates a second job, and a second charge.

How a blank key happens

  • An environment variable such as JOB_KEY is unset, and the template renders an empty string.
  • A key read from a record field that is missing, for example (row.get("key") or "").strip().
  • A no-code tool sends the header with an empty mapped value.

What the API does with the header

The API handles the header in two ways. A missing header or a blank one means no idempotency. A value longer than 255 characters, or one with control characters, returns 400 invalid_request. The valid range is 1 to 255 printable characters, so the blank case is the one that fails silently.

A key that cannot be empty

Derive the key from the content of the work and hash it. The hash is always 64 characters, it is stable across retries, and an empty input still produces a key, so the blank case is impossible. The function refuses a blank label because a label is how you tell two jobs apart.

import hashlib, json

def idempotency_key(namespace, **fields):
    """Same inputs, same key. Different inputs, different key. Never blank."""
    if not namespace.strip():
        raise ValueError("namespace must not be blank")
    payload = json.dumps(fields, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(f"{namespace}\n{payload}".encode()).hexdigest()

k1 = idempotency_key("avatar-batch-2026-10", sku="A-100", variant="red")
k2 = idempotency_key("avatar-batch-2026-10", sku="A-100", variant="red")
k3 = idempotency_key("avatar-batch-2026-10", sku="A-100", variant="")
print(k1 == k2, k1 == k3, len(k1))  # True False 64

Check before you send

Assert 1 <= len(key) <= 255 in your HTTP wrapper before every POST that you might retry. The same key with a different body returns 409 idempotency_conflict, so build the key from the fields that define the job. Never reuse one key across different work.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume