GitHub Actions if Condition Always Runs or Never Runs
A step or job if condition evaluates the wrong way because the expression is a non-empty string that is always truthy, or because of a type or operator mistake.
What this error means
A step with an if condition runs on every event when it should be gated, or is skipped when it should run. The workflow is valid, but the condition does not behave as intended.
# this string is always truthy, so the step always runs
- run: ./release.sh
if: ${{ github.ref == 'refs/heads/main' }} || trueCommon causes
Trailing text makes the condition a non-empty string
GitHub treats a non-empty string as true. Text after the ${{ }} expression, or a stray operator, turns the whole condition into a constant truthy string.
Wrong comparison or context value
Comparing github.event_name to the wrong literal, or using == where the value differs in case or format, makes the condition never match.
How to fix it
Write the whole condition as one expression
Keep everything inside a single ${{ }} (or omit the braces entirely for the if key) so the result is a real boolean, not a string.
- run: ./release.sh
if: github.ref == 'refs/heads/main' && github.event_name == 'push'Verify the context values you compare against
- Print the value first with a debug step, for example run: echo "${{ github.ref }}".
- Match the exact format: github.ref is refs/heads/main, not main.
- Use the documented functions (contains, startsWith) instead of brittle string equality.
How to prevent it
- Prefer the bare expression form for if, and keep the entire condition inside one expression.
- Echo context values in a debug run before relying on them in a condition.
- Use contains() and startsWith() for partial matches rather than ==.