The expectation in modern DevOps is linear and predictable: a code change initiates a pipeline, the pipeline executes, and subsequent steps follow logically. In the context of GitHub Actions, this linear assumption often leads to frustration when workflows remain stubbornly inactive despite seemingly correct configurations. Developers frequently encounter scenarios where a scheduled task runs but fails to trigger a downstream deployment, or a workflow updates a repository branch yet fails to ignite the associated build pipeline. These silent failures are rarely the result of bugs in the user’s YAML syntax. Instead, they are the direct consequence of deliberate architectural safeguards designed to prevent infinite recursion and protect repository integrity. Understanding the nuanced behavior of the GITHUB_TOKEN, the structural requirements of workflow files, and the specific triggers required for inter-workflow communication is essential for diagnosing and resolving these common operational deadlocks.
The Recursion Prevention Mechanism
The most frequent cause of confusion regarding non-triggering workflows is the behavior of the default authentication token provided by GitHub. When a workflow is configured to push changes back to the repository—such as updating a configuration file, bumping a version number, or merging a branch—it often fails to trigger a subsequent workflow that listens for push events. This behavior is not an oversight; it is a fundamental security and stability feature.
By default, GitHub provides a GITHUB_TOKEN to every workflow run. This token is a GitHub App token that automatically expires when the workflow completes. While this token grants read and write permissions to the repository where it is generated, it is specifically engineered to ignore webhook triggers. If a workflow pushes a commit using the GITHUB_TOKEN, the resulting push event is deliberately filtered out so that it does not start another workflow. This design prevents infinite loops where a workflow triggers itself recursively, potentially exhausting runner minutes or causing cascading failures.
For instance, consider a scenario where a workflow named update-theme-color runs on a schedule, modifies a configuration file, and pushes the change to the master branch. An intuitive assumption would be that this push should trigger a second workflow named publish, which is configured to run on pushes to master. In reality, the publish workflow will not start because the push originated from the GitHub App token. To resolve this, developers must either use a different authentication method, such as a Personal Access Token (PAT) with appropriate scopes, or restructure the workflow logic to explicitly listen for the completion of the upstream workflow rather than the push event itself.
Inter-Workflow Triggering with workflow_run
When one workflow needs to trigger another, relying on the push or pull_request events triggered by the default token is ineffective. The correct architectural pattern for chaining workflows is the workflow_run event. This event allows a workflow to listen for the completion status of another specific workflow. This approach decouples the actions and ensures that the downstream workflow only executes after the upstream workflow has successfully finished, regardless of whether the upstream workflow made commits to the repository.
To implement this, the downstream workflow must include the workflow_run trigger and specify the name of the upstream workflow it wishes to monitor. The configuration must explicitly list the workflow names and the desired status types, such as completed or success. This method is robust because it does not rely on the repository’s commit history or the permissions of the GITHUB_TOKEN. Instead, it relies on the metadata of the workflow runs themselves.
yaml
name: publish
on:
push:
branches:
- master
workflow_run:
workflows: ["update-theme-color"]
types:
- completed
In the example above, the publish workflow will trigger both on manual pushes to the master branch and when the update-theme-color workflow completes. This dual-trigger configuration ensures that human-initiated changes are processed immediately, while automated changes from the scheduled task are also captured. It is critical to note that the workflow_run event requires the specified workflow names to match exactly as they appear in the repository. Any discrepancy in naming will result in the trigger being ignored.
Authentication Strategies for Triggering Pushes
When the workflow_run event is not suitable, and a developer must push changes to trigger another workflow, they must bypass the GITHUB_TOKEN's webhook suppression. The primary method for achieving this is by using a Personal Access Token (PAT) or a GitHub App token that is not the default GITHUB_TOKEN. However, even with a PAT, the checkout action can inadvertently interfere with the process.
The actions/checkout action, particularly version 2 and later, has a default setting called persist-credentials that is set to true. This setting saves the credentials used for the checkout so that subsequent git commands can use them without explicit configuration. If the workflow is using the default GITHUB_TOKEN for the checkout, and then later switches to a PAT for the push, the git configuration might still be pointing to the GITHUB_TOKEN or conflicting credentials. To ensure that the push is made with the intended PAT and triggers the downstream workflow, the persist-credentials flag should be set to false during the checkout step.
yaml
- uses: actions/checkout@v2
with:
persist-credentials: false
By disabling credential persistence, the workflow ensures that the subsequent git push command uses the explicitly configured PAT. This PAT, unlike the GITHUB_TOKEN, does not have its push events suppressed. Consequently, the push will generate a standard webhook event, and any workflow listening for pushes to that branch will execute as expected. This technique is particularly useful in scenarios where a workflow needs to update a different branch or repository and trigger builds there.
File Location and Repository Structure
A more elementary but surprisingly common cause of non-triggering workflows is the incorrect placement of the workflow file. GitHub Actions workflows must be stored in a specific directory to be recognized by the platform. The directory structure is strict: the file must be located in .github/workflows/. Note that the directory name is workflows, plural. Placing the file in .github/workflow (singular) or any other custom directory will result in the file being ignored by the GitHub Actions engine.
When creating a new workflow, developers often rely on the GitHub UI, which guides them to the correct location. However, when cloning a repository or creating files via the command line, it is easy to make a typo or misplace the file. If the workflow file is not in the correct directory, it will not appear in the "Actions" tab of the repository, nor will it be listed in the repository settings under "Actions" > "Workflow permissions". The absence of the workflow in the UI is a strong indicator that the file is either in the wrong location or has an invalid YAML syntax that prevents parsing.
text
.github/
workflows/
ci.yml
deploy.yml
Ensuring the file is in the .github/workflows/ directory is the first step in troubleshooting. If the file is present and valid, it should be visible in the Actions tab, even if no runs have been executed yet. If it is not visible, the path is likely incorrect.
Scheduled Workflows and Cron Jobs
Scheduled workflows, defined using the schedule trigger and cron syntax, are another area where developers encounter issues. A common complaint is that a scheduled workflow does not run at the expected time, even though the cron syntax is correct. Unlike manual triggers or push events, scheduled runs are subject to the overall health and availability of the GitHub Actions service.
Before investigating local configuration issues, it is prudent to check the GitHub Status page. Outages or degraded performance in the GitHub Actions service can delay or prevent scheduled runs. These outages are not rare; they occur periodically due to the scale of the service. During an outage, scheduled workflows may not execute, or they may run with significant latency.
Furthermore, the permissions required for scheduled workflows are similar to other workflows. The workflow must have the necessary permissions to execute its steps. If the repository settings restrict workflow permissions, the scheduled run may fail silently or fail to perform its intended actions. Ensuring that "Workflow permissions" are set to "Read and write permissions" in the repository settings is crucial for workflows that need to interact with the repository, such as creating issues, updating files, or triggering other workflows.
Pull Request and Feature Branch Considerations
The behavior of workflows also changes depending on the branch context and the source of the push. When working with pull requests, workflows are typically triggered by push events to the feature branch or by the opening of the pull request itself. However, if a workflow running on the feature branch pushes new commits to that same branch, the subsequent push event will not trigger another run of the same workflow, due to the GITHUB_TOKEN suppression mechanism described earlier.
This is particularly relevant in scenarios where a workflow needs to amend a commit or add a changelog to a feature branch. If the workflow uses the default GITHUB_TOKEN to push these changes, the workflow will not run again to validate the new commit. To circumvent this, developers must use a PAT or the workflow_run event to handle the validation of the amended commits.
Additionally, the branch protection rules can impact workflow execution. If a branch requires status checks to pass before merging, and the workflow is responsible for running those checks, a deadlock can occur if the workflow fails to trigger. Ensuring that the workflow is configured to run on the correct branch and that the permissions are adequate is essential for maintaining a functional CI/CD pipeline.
Conclusion
The phenomenon of GitHub Actions failing to trigger is rarely a bug in the platform but rather a result of interacting with its safety mechanisms and configuration requirements. The default GITHUB_TOKEN is designed to prevent infinite recursion by suppressing webhook triggers for pushes it initiates. This necessitates alternative strategies for chaining workflows, such as using the workflow_run event for logical dependencies or employing Personal Access Tokens with persist-credentials: false for direct push triggers. Furthermore, basic structural issues, such as incorrect file placement in the .github/workflows/ directory, and external factors like service outages, must be ruled out before assuming a complex configuration error. By understanding these underlying principles, developers can design robust, predictable, and efficient CI/CD pipelines that leverage the full power of GitHub Actions without falling into common operational pitfalls.
Sources
- Why your GitHub Action is not triggered by other actions
- GitHub Community Discussion: Scheduled GitHub Actions workflow not triggering
- GitHub Community Discussion: Workflow not triggering on push to main
- Workflows not starting
- GitHub Community Discussion: Push from action does not trigger action
- GitHub Push Action Issue: Push not triggering workflow