Claude batch custom_id is 64 characters: keep SKU keys valid
Anthropic batch custom_id allows 1 to 64 letters, digits, underscore and hyphen. How to sanitize SKUs, avoid collisions and carry the key into Sume input.

What does a valid Claude batch custom_id look like? On Anthropic's batch page (read 2026-10-04) it is 1 to 64 characters matching ^[a-zA-Z0-9_-]{1,64}$. A retailer SKU like MUG/12 oz #4 fails that rule on three characters, so the key you use to find a result later has to be derived, not copied.
Sume has no custom_id. A bulk queue is ordered, and each item is a Format run body, so the SKU belongs in the item's input object, where you choose the shape. The two systems want the same discipline: one stable key per row, made before you submit.
Three ways a SKU breaks a key
- Characters outside letters, digits, underscore and hyphen, such as slashes, spaces and hash signs.
- Length over 64, which happens with descriptive SKUs that include colour and size words.
- Collisions after cleanup:
MUG 12andMUG/12both becomeMUG-12if you only replace bad characters.
Sanitize without collisions
The safe approach is to replace bad characters, then append a short counter only when the cleaned key was already taken. Store a map from the clean key back to the raw SKU, and use that map when results arrive. The script below does exactly that and then asserts every key passes Anthropic's pattern.
import re
PATTERN = re.compile(r"^[a-zA-Z0-9_-]{1,64}$")
skus = ["MUG/12 oz #4", "MUG 12 oz #4", "x" * 80, "scarf_red"]
seen, back = {}, {}
for raw in skus:
key = re.sub(r"[^a-zA-Z0-9_-]+", "-", raw).strip("-")[:60] or "item"
n, candidate = 1, key
while candidate in seen:
n += 1
candidate = f"{key}-{n}"
seen[candidate] = raw
back[candidate] = raw
assert PATTERN.match(candidate), candidate
for k, v in back.items():
print(k, "<-", v[:20])Round trip: from result back to your catalog
After the batch ends, each result line comes back with the same custom_id you sent, so the back map in the script turns it into your raw SKU. Anthropic marks every result as succeeded, errored, canceled or expired, and only succeeded ones carry text you can use. Collect the other three into a retry list and resubmit them as a new batch with the same cleaned keys, so the map stays valid.
On the Sume side the same discipline applies to the queue. Build the list of items from your clean keys in a fixed order, send it, and keep that order. The queue's items[i] is your i-th row, so back is indexed by position rather than by a label. If you ever need to split a job into several queues of 100, record the starting offset of each queue next to its frq_ id.
Neither system rewards creative keys. A boring, derived, reversible key is what lets a holiday job with thousands of rows survive a restart halfway through.
Carry the key into a Sume item
When you turn succeeded batch results into a bulk request, copy the clean key into input. The Format reads the keys it knows and ignores the rest, so input.sku is free metadata for your logs. The key is a convention of yours: Sume does not return it as a join field, so you still join on item index, which is the position you submitted.
One more difference: Anthropic lets results arrive in any order and you join on custom_id; Sume returns items in submission order. Both lookups are exact, which is why a sanitised key map is worth the five lines.
Limits side by side
| Anthropic Message Batches | Sume bulk run | |
|---|---|---|
| Row key | custom_id, 1 to 64 characters | None; use item index |
| Allowed characters | Letters, digits, underscore, hyphen | Any, inside input |
| Where your own SKU goes | custom_id | input object of each item |
| Rows per submission | Up to 100,000 requests | 1 to 100 items |
Sources
Related posts
More in Developers
- Claude Code 2.1.285 lists WebSocket MCP servers; Sume uses HTTP
Claude Code 2.1.285 shows WebSocket MCP servers in claude mcp list. Sume's hosted MCP is a remote HTTP server, added with --transport http.
- MCP error text showed a Bearer token: rotate the Sume API key
Claude Code 2.1.286 masks credentials after Bearer or Basic in MCP errors. If an old log shows a Sume key, replace it and keep keys out of logs.
- Claude Code scope re-authenticate prompt vs unattended Sume runs
Claude Code 2.1.288 prompts to re-authenticate when a server asks for more OAuth scope. Unattended runs cannot answer it, so grant write up front.
- Claude Code 2.1.289 plugin loading fix: recheck Sume MCP after upgrade
Claude Code 2.1.289 fixed plugin loading after an upgrade. A four-call read-only check confirms the Sume MCP connection and scopes before you run a paid job.
Written by Sume