Skip to main content
A scheduler manifest is the unit of work for every command in this group. It names one scheduler blob and one revision, and lists every schedule that belongs on that revision. There is no per-schedule manifest and no default path — -f/--file is required everywhere, and the file it names is loaded before anything else happens. The file is parsed by extension: .yaml, .yml and .json all work, and the same manifest written in YAML or in JSON loads identically. An unsupported extension is FORMAT_UNSUPPORTED; a file that does not parse is FORMAT_PARSE_ERROR.

The shared base

scheduler_blob_deployment is the second manifest type over the shared base the workflow manifest introduces. The base is parsed and validated by itself, before the body is looked at, and type is what selects the body — so these four fields mean here exactly what they mean there.
The blob’s type is confirmed before any data command: a scheduler manifest pointed at a workflow blob stops with BLOB_NOT_WORKFLOW — one shared resolver raises that code for every group, and its message names both the shape found and the shape expected. A scheduler blob is created in phase managed and holds a single revision, always, so revision: default is the normal value and names the one revision there is. Pinning a UUID is legal and does exactly what it does in the workflow group.

The scheduler_blob_deployment body

One key: schedules, a list. Unlike the workflow body’s definitions, an empty list is valid — a revision holding no schedules is an ordinary state, and an empty schedules: [] is precisely the document pull writes for one. A missing key is still MANIFEST_INVALID: absent is a manifest that says nothing about schedules, empty is one that says there are none. A schedule entry carries exactly the create_schedule fields, under the platform’s own names: The CLI carries every time and date field through as an opaque string and checks none of their contents, so the naive/UTC split above is the platform’s rule, enforced where the schedule is written rather than where it is authored. Every level of this document rejects a key it does not list — an entry’s own fields, and likewise invocation_target’s and its target’s — so a typo’d field name is MANIFEST_INVALID rather than silently inert. There is no schema beyond what is described here.

repeat decides which timing field exists

repeat gives exactly one of cron_expression and invocation_time meaning, and the manifest must carry that one and only that one. A recurring_cron entry without a cron_expression, or a one_time entry without an invocation_time, is MANIFEST_INVALID. So is an entry carrying both. Refusing both is worth the extra rule. The likeliest way to arrive there is the half-finished edit that flips repeat and leaves the old kind’s field behind — and the field left behind can never take effect, never be reported as differing, and can never be removed from a deployed schedule either: update_schedule sets only the keys it is sent and rejects a null, so a record flipped from recurring_cron to one_time keeps its stale cron_expression for good. Only the field repeat gives meaning to is compared, by diff and deploy alike.

The invocation_target block

invocation_target is the API’s own object, carried into the manifest field for field — the same one Create Schedule and Invocation Targets describe. It has exactly three keys, and neither it nor its nested target admits one it does not list. target has the following fields. Each part present is a non-blank string of at most 64 characters, checked before any of the rules below; a blank or over-long value is MANIFEST_INVALID naming the field. input_data is the one field nothing checks until the schedule fires. The scheduler’s own schema types it as a bare array, so create_schedule accepts any list at all; the item shape — {"alias": "<component alias>", "value": {"type": …}}, documented under Create Execution — is enforced by create_execution at fire time, where a violation surfaces as an invocation_error on the schedule’s execution history rather than as a failed deploy.

The retired layout

The retired layout put a schedule entry’s own target: block one level up, with workflow as a path string and a blob addressed as an org/blob string inside it. Every one of these is refused at load — MANIFEST_INVALID, before any network call — each message naming the field’s new home. Only an entry-level target: hints blobhub scheduler pull -f <path>, since pull reads only the manifest’s base and can safely rewrite the whole entry from what is deployed. A retired key found inside a target that already sits under invocation_target, a string invocation_target.workflow, or an org/blob string in invocation_target.target.blob hints blobhub scheduler diff -f <path> instead and is fixed by hand, because pull would replace the file and drop its undeployed entries. An entry-level target: is caught before the generic unknown-field check, so its message names the new layout rather than listing target as an unrecognized field. A retired key found inside a target that already sits under invocation_target, a string invocation_target.workflow, and an org/blob string in invocation_target.target.blob are each caught in their own check and hint diff, not pull — the same remedy latest → default uses elsewhere in this manifest — since only an entry-level target: is safe for pull to rewrite wholesale.

Seven constraints, checked before anything is written

These seven are answered offline, at load time, before a single schedule is created or updated. They are checked locally rather than left to the server for one reason: deploy writes entries in order, so a manifest whose second entry breaks a rule the platform enforces would deploy the first and then fail — leaving a half-deployed set that is already firing on its cron. alias is required on every entry, which the platform does not require of a schedule — it is the manifest’s identity for one, and what makes a second deploy an update rather than a duplicate. cron_expression and timezone are the one class of failure the CLI cannot catch beforehand. Neither is constrained by any schema, and the CLI passes both through as opaque strings. They are validated when the schedule is written:
  • The platform itself answers the two cron mistakes that are common and badly reported downstream — an expression that is not exactly six space-separated fields, and one where day-of-month and day-of-week are not exactly one ? between them. Both come back as invalid_cron_expression. The plausible-looking 0 9 * * MON-FRI * is the second of those; 0 9 ? * MON-FRI * is the working form.
  • Everything else — ranges, steps, month and day names, out-of-range values, and the timezone, which is handed straight to the scheduling service as its ScheduleExpressionTimezone — is the scheduling service’s own rejection, surfaced with its message.
So a bad cron or timezone on a later entry can leave earlier entries deployed, which is the gap the constraints above exist to keep as small as possible. Check the syntax against cron expressions before deploying a set.

A worked example

A scheduler blob acme-corp/checkout-ops carrying two schedules against the workflow blob acme-corp/checkout: a recurring one that runs every morning in New York time against a session it shares with every other run, and a one-time launch pinned to a specific revision, with input data and a description.
Both files load to the same manifest. Both entries name the target blob the same way, org: acme-corp beside the alias blob: checkout — unlike the retired layout, nothing here inherits the manifest’s own top-level blob’s org, so a target blob named by alias always spells its own org out. The second entry’s pinned target.revision is worth one note. It is stored on the schedule exactly as the manifest wrote it: default stays the literal word, and a pinned UUID stays that UUID — the platform never resolves one into the other, so pull reads a target back unambiguously as following or pinned, matched by the schedule’s alias, with no guessing involved.

A cross-blob workflow

invocation_target.workflow can name a definition outside the target blob entirely:
The session still runs in checkout; the definition it runs comes from shared-procedures. See The workflow reference.

Errors

Every code above, with its remediation, is in Error codes.

See also

  • Scheduler overview — the two blobs one deploy touches, and the four commands that manage them.
  • Workflow manifest — the same shared base, with the workflow_blob_deployment body over it.
  • Scheduler blob type — cron syntax, timezones, date windowing, alias grammar and schedule states, as the platform defines them.
  • Concepts — why a manifest is revision-scoped, and why drift in this group is not inert.