# GitHub Actions on section missing from a workflow file

> A GitHub Actions on section missing from a file is fatal even though the published schema does not mark it required. Here is which layer refuses it.

Source: https://latchkey.dev/learn/github-actions/github-actions-on-missing-triggers  
Updated: 2026-09-21

A GitHub Actions on section missing from a workflow file ends the run before it starts, and the layer that refuses it is not the one most people assume. The published schema marks only the jobs key as required at the workflow root, so the refusal comes from GitHub rather than from anything in the parser you can read.

## What this error means

Every push to every branch produces a failed check against a workflow you did not think was running. That is the shape worth recognizing, because a workflow with no usable trigger does not quietly sit there: it is evaluated, found unusable and reported, on every push, forever. The file is often one somebody meant to disable. Commenting the whole thing out, emptying it while leaving it in place, or deleting the contents and keeping the name all produce the same result, which surprises people who expected an empty file to be ignored.

```Quoted from susam.net, Minimal GitHub Workflow, a recorded experiment on a zero-byte workflow file
Error
No event triggers defined in `on`
```

## Common causes

### The trigger block was commented out to disable the workflow

The commonest origin by a distance, and the one place the wording of the edit decides which message you get. Comment out the key along with its events and no key is left, which is this message. Comment out only the events, as below, and the key survives with nothing under it, which the ladder answers differently. Either way the file fails against every push rather than doing nothing, which is the opposite of the intent.

```Illustrative workflow fragment
# the trigger key survived, every event under it did not
on:
#  push:
#    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo hello
```

### The file was emptied but not deleted

A commit that strips the contents and leaves the path in place. The diff reads as a deletion in review, and the zero byte file is still evaluated on every push.

### The trigger key drifted out of the root mapping

One extra level of indentation puts it inside another key. The YAML is valid, the block looks right in isolation, and the root genuinely has no trigger.

### The file is not a workflow at all

A template, a fragment or an editor configuration file stored in the workflows directory. Everything in that directory is treated as a workflow, so a file that was never meant to be one fails as one.

## How to fix it

### Decide whether the workflow should exist

1. If it should run, restore a trigger block at the root of the file.
2. If it should not run for now, disable the workflow rather than editing it.
3. If it should never run again, delete the file.
4. If it is not a workflow, move it out of the workflows directory.

### Restore a trigger at the root, not inside another key

Check the indentation of the trigger key against the jobs key. Both belong at column one, and a trigger that is indented further is inside something else regardless of how correct the block under it looks.

```.github/workflows/ci.yml
on:
  push:
    branches: [main]
  pull_request:

jobs:
  build:
    runs-on: ubuntu-latest
```

### Disable rather than comment out

Disabling leaves the file intact and stops it being considered, which is what commenting out the events was trying to achieve. It is reversible from the same command.

```shell
gh workflow disable ci.yml
gh workflow enable ci.yml
```

### Keep non workflow files out of the workflows directory

Templates and fragments belong beside it, not in it. A directory whose every file is a workflow is one fewer thing to explain to the next person who adds a file there.

## How to prevent it

- Never disable a workflow by commenting out its trigger block.
- Treat an emptied workflow file in a diff as a file that still runs.
- Keep only real workflows in the workflows directory.
- Check that the trigger key and the jobs key sit at the same indentation.

## What the published schema actually requires

Follow the workflow root definition in the schema that ships in the runner and the list of properties is short: the trigger key, a name, a description, a run name, defaults, env, permissions, concurrency and jobs. Exactly one of them carries the required flag, and it is jobs. The trigger key is listed as an ordinary optional property.

The editor copy of the schema in the language services repository has the same root definition with the same single required property, which is why an editor extension does not warn you about a file with no trigger. Both published parsers will read such a file without objecting.

The refusal therefore happens somewhere else. GitHub evaluates the file when it decides which workflows a push affects, and a file that offers no usable event is reported at that point. That component is not published, so the honest statement is that the rule is GitHub behavior rather than parser behavior.

The message it produces is the one quoted above, and what it leaves out is the diagnosis. There is no file path, no line and no column, which is unusual for this validator: the key is not there to point at. A recorded experiment that walked a workflow file up from zero bytes got those two lines from the empty file, and something else from the next rung, where the key exists with nothing under it. That rung gets the ordinary shape, a position and an unexpected empty value, because an empty value is a value. So the distinction that matters is whether the key survived, and parentheses and numbers in your annotation mean it did.

The rest of this page is the other half: why the file looks fine to every tool you have locally, and which edits produce it.

| Layer | Requires a trigger | What it does with a file that has none |
| --- | --- | --- |
| YAML parsers generally | no | parses it, no complaint |
| The published workflow schema | no, only jobs is required | reads it, no complaint |
| The editor schema copy | no, the same root definition | no warning in the editor |
| GitHub, when deciding what a push runs | yes | reports it against every push |

> Three of the four rows are quiet, which is why the failure only ever appears once the file is pushed, and appears on every push after that.

## The quoting advice, and why it does not apply here

There is widespread advice to quote the trigger key because YAML will otherwise read it as a boolean. That advice has a real origin and it does not apply to this parser, which is worth stating plainly because acting on it wastes time you could spend on the actual cause.

The runner YAML reader resolves plain scalars using the YAML 1.2 core schema, and the source says so in a comment with a link to the specification. Its boolean matcher accepts six spellings and no others: true, True, TRUE, false, False and FALSE. The words on, off, yes and no are not among them, so the trigger key is read as the ordinary string it looks like.

The advice comes from YAML 1.1, where those four words are booleans, and from the many tools that still implement it. A script that loads your workflow with a 1.1 parser really does see a key that is not the trigger key, and linters warn about it for that reason. That is a fact about your tooling, not about GitHub, and quoting the key is harmless but it will not fix a missing trigger.

```YAML 1.2 core schema, as implemented in the runner reader
# the runner reads these six spellings as booleans, and no others
true   True   TRUE   false   False   FALSE

# so this key is a string to the workflow parser
on:
  push:
    branches: [main]
```

## The edits that produce it

Commenting out the trigger block is the first. Somebody wants to stop a workflow temporarily, comments out the events and leaves the key, and now the file has a trigger key with nothing under it. Reports of this describe a failure on every push to every branch, which is exactly what it should do, and it is startling because the intent was to make the workflow stop.

Emptying the file is the second. A commit that removes the contents of a workflow and leaves a zero byte file behind produces the same thing, and the diff looks like a deletion, so reviewers read it as one.

Indentation is the third and the least obvious. A trigger key that has drifted one level in, so that it sits under something else rather than at the root, is a perfectly valid mapping in the wrong place. The root then has no trigger key, and the misplaced one is a stray key inside whatever now contains it.

The remedy for all three is the same and it is not to edit the trigger block. If you want a workflow to stop running, delete the file or disable the workflow, which are both operations that leave nothing behind to be evaluated on every push.

```shell
# stop a workflow without leaving a file that fails on every push
gh workflow disable ci.yml

# or remove it entirely
git rm .github/workflows/ci.yml
```

## Why there is no recorded run on this page

A workflow with no usable trigger does not produce a run with jobs in it, so there is no log to capture. The observable artifact is a failed check attached to a commit, and a capture of ours would show our repository name and our commit, which carries no information about yours.

The parts of this page that can be established from published sources are established from them: the single required property at the workflow root is read out of both copies of the schema, and the six boolean spellings are read out of the reader that implements the YAML 1.2 core schema. The part that cannot be, which is what GitHub does with the file, is labeled as GitHub behavior rather than dressed up as parser behavior.

Nothing here is repairable by a runner. No runner is ever handed this workflow, because the decision is made before any job is created.

## FAQ

### Is the on key required in a GitHub Actions workflow?

Not by the published schema, which marks only the jobs key as required at the workflow root, and the editor copy of that schema agrees. The requirement is applied by GitHub when it decides which workflows a push affects, which is why no local tool warns you.

### Do I need to quote the on key so YAML does not read it as true?

Not for GitHub. The runner reader follows the YAML 1.2 core schema and its boolean matcher accepts only true, True, TRUE, false, False and FALSE. The advice comes from YAML 1.1 parsers, which many other tools still use, so quoting helps those tools and changes nothing here.

### Why does an empty workflow file fail on every push?

Because every file in the workflows directory is evaluated when a push arrives, and one that offers no usable event is reported then. Emptying a file does not remove it from consideration, so the failure repeats on every push until the file is deleted or the workflow is disabled.

### Is this the same as writing the trigger key with nothing under it?

No, and the annotation tells you which you have. A key present with an empty value is answered with a line, a column and an unexpected empty value, because an empty value is still a value. The message about no event triggers carries no position at all, which is the state where the key itself is absent.

### How do I stop a workflow without breaking every build?

Disable the workflow, or delete the file. Both leave nothing that has to be evaluated on each push. Commenting out the events is the one option that keeps the file in play while making it unusable.

## References

- [actions/runner: the published workflow schema, workflow-root and its one required property](https://github.com/actions/runner/blob/main/src/Sdk/WorkflowParser/workflow-v1.0.json)
- [actions/runner: YamlObjectReader.cs, the YAML 1.2 core schema boolean matcher](https://github.com/actions/runner/blob/main/src/Sdk/WorkflowParser/Conversion/YamlObjectReader.cs)
- [GitHub Actions: workflow syntax, on](https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#on)
- [GitHub Actions: disable and enable a workflow](https://docs.github.com/en/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows)
- [susam.net, Minimal GitHub Workflow: the recorded ladder from a zero-byte file upward](https://susam.net/minimal-github-workflow.html)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
