YouTube publishAt in the past publishes now: a guard for batches

The Videos resource says a past publishAt publishes the video immediately, and it works only on private videos. A Python guard for scheduled Shorts batches.

5 min readSume
All posts

If you set status.publishAt to a time that has already passed, YouTube publishes the video immediately instead of scheduling it. The same field can be set only when the video's privacy status is private. When you upload a batch of Shorts that Sume produced overnight, a slow render or a timezone slip can turn a week of scheduled releases into fifteen instant posts, so check the value before you send it.

Both rules come from the Videos resource and the videos.insert reference, read on 2026-10-02.

What do the two rules say, exactly?

For status.publishAt, the Videos resource page says it is the date and time the video is scheduled to publish, that it can be set only if the privacy status is private, and that a past date triggers immediate publication. The insert reference lists status.privacyStatus and status.publishAt among the properties you can set on upload.

That gives a pairing rule for your body: a scheduled upload is privacyStatus: private plus a future publishAt. A past time publishes the video at once, and a non-private video cannot carry the field.

publishAt and privacyStatus combinations (read 2026-10-02)
What you sendDocumented result
private with a future publishAtScheduled
private with a past publishAtPublishes immediately
public or unlisted with publishAtNot allowed: the field can be set only on private videos
No publishAtUses privacyStatus as sent

Why do Sume batches make this more likely?

A Format bulk run queues up to 100 runs behind a concurrency window, and each child finishes when it finishes. If you compute the publish time when a render lands rather than when you plan the calendar, a delay moves the slot into the past. Compute the schedule once, at planning time, and store it next to the job id.

The jobs guide says a non-terminal job should be polled, not resubmitted. That also protects the calendar: a resubmitted render is a second video with its own slot.

A guard you can run

This function refuses a past time and a missing privacy pairing, and returns the status body to send. Times are UTC ISO strings, the common form for this field.

from datetime import datetime, timezone, timedelta

def scheduled_status(publish_at_iso, now=None, min_lead_minutes=15):
    now = now or datetime.now(timezone.utc)
    when = datetime.fromisoformat(publish_at_iso.replace("Z", "+00:00"))
    if when < now + timedelta(minutes=min_lead_minutes):
        raise ValueError(f"{publish_at_iso} is too close or past: YouTube would publish now")
    return {"privacyStatus": "private", "publishAt": publish_at_iso}

now = datetime(2026, 10, 2, 12, 0, tzinfo=timezone.utc)
print(scheduled_status("2026-10-05T16:00:00Z", now))
try:
    scheduled_status("2026-10-01T16:00:00Z", now)
except ValueError as e:
    print("refused:", e)

How far ahead should a slot be?

The guard above uses a 15-minute minimum lead. That number is ours, not YouTube's: the page says only that a past date publishes immediately. We chose a margin because your own clock, a slow upload, or a retry can eat a few minutes between computing the time and the API receiving it.

For a weekly series, keep the schedule in one list in your own system, with the Sume job id and the planned slot per row, and generate the status body from that list at upload time. Never derive the slot from the time a render finished.

What should I still verify by hand?

Upload one test Short with a schedule an hour out and read the video back to confirm it shows as scheduled. If your uploads from an unverified API project all come back private, that is a separate rule; see our post on the unverified project lock. Sume does not schedule or publish to YouTube; the upload call is yours.

The pages we read do not describe an undo for an early publish, and anyone who watched in the meantime has seen the video. That is why the guard raises an error instead of silently moving the slot: a refused upload is easy to retry, and an early public post is not.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume