Set timeout for CI by ShaharNaveh · Pull Request #5947 · RustPython/RustPython
@ShaharNaveh You're absolutely right! I apologize for the incorrect assessment. GitHub Actions does indeed support expressions in the timeout-minutes field, and your expression ${{ contains(matrix.os, 'windows') && 40 || 30 }} will correctly evaluate to 40 minutes for Windows runners and 30 minutes for other OS runners.
Thank you for the correction - the workflow syntax is perfectly valid as implemented.
🌐 Web query:
GitHub Actions timeout-minutes expression support documentation
💡 Result:
GitHub Actions' timeout-minutes does not fully support expressions like repository or environment variables without specific type conversion workarounds. Here are the facts and the current documentation status:
- The
timeout-minutesparameter sets the maximum number of minutes a job can run before GitHub cancels it. The default is 360 minutes (6 hours), but you can increase or decrease this limit as needed within the permitted range[1][4][10]. timeout-minutesmust be a numeric literal or an expression that resolves to a number. If you attempt to set it directly using a repository or environment variable (e.g.,timeout-minutes: ${{ vars.TIMEOUT }}), you may encounter a workflow syntax error if the value is interpreted as a string or is not properly cast to a number[3].
The error you are encountering when using a repository variable for timeout-minutes in GitHub Actions is likely due to the fact that timeout-minutes requires a numeric value. If the repository variable you are using is not numeric or is not being passed as a numeric value, you will receive an error.[3]
-
Workaround:
You can use thefromJSON()function to convert strings that contain numbers to a numeric value, making it possible to use expressions fortimeout-minutes:timeout-minutes: ${{ fromJSON(vars.TIMEOUT) }}
This treats a string like
"10"as the number10, which is accepted by the workflow syntax[3]. -
Documentation coverage:
The official [GitHub Expressions Documentation][2][8] describes how expressions are used generally—including in workflow conditions, environment variables, and other parameters—but it does not explicitly document thattimeout-minutesrequires a numeric type or how to use type conversion workarounds. -
Global/default setting:
Settingtimeout-minutesin thedefaultsblock at the workflow level is not supported; it must be set at the job level. Only keys underdefaults.runare currently accepted[6][9].
In summary:
- Expressions can be used with
timeout-minutesif the result is numeric; ensure type conversion when using variables[3]. - Direct variable substitution may fail unless handled with
fromJSON()for type conversion[3]. - No workflow/global-level default for
timeout-minutes—set per job[6]. - The GitHub Docs cover general expressions usage[2][7][8] but do not specifically document this corner case for
timeout-minutes.
References for further details:
- [GitHub Docs: Expressions][2][8]
- [Community workaround with fromJSON()][3]
- [Workflow syntax reference for job timeouts][4][6][9]
Citations:
- 1: https://dev.to/suzukishunsuke/set-github-actions-timeout-minutes-1jkk
- 2: https://docs.github.com/en/actions/concepts/workflows-and-actions/expressions
- 3: https://github.com/orgs/community/discussions/55332
- 4: https://drdroid.io/stack-diagnosis/github-actions-timeout-exceeded
- 5: https://docs.github.com/en/actions/reference/metadata-syntax-for-github-actions
- 6: https://github.com/orgs/community/discussions/25472
- 7: https://docs.github.com/en/actions/reference/contexts-reference
- 8: https://docs.github.com/en/enterprise-server@3.13/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions
- 9: https://github.com/orgs/community/discussions/10690
- 10: https://github.com/orgs/community/discussions/27177
🌐 Web query:
GitHub Actions timeout-minutes ternary operator expression "contains && ||" syntax
💡 Result:
GitHub Actions expressions do not support a native ternary operator (? :) syntax, but you can achieve similar behavior using the && and || logical operators in combination. This pattern is commonly referred to as a "fake ternary" in the GitHub Actions community[1][5][6].
Syntax for Ternary-like Expressions
The general syntax is:
${{ condition && value_if_true || value_if_false }}- If condition evaluates to a truthy value, the result is value_if_true.
- If condition is falsy (
false,0,'',null), the result is value_if_false.
For example, to conditionally set a parameter based on input:
run: npm run build ${{ inputs.production == 'true' && '--production' || '' }}
This adds --production if inputs.production is 'true', otherwise adds nothing[1][3].
Important Caveats
- The value_if_true part must not be a falsy value (like
''orfalse)—otherwise the expression will incorrectly fall through to value_if_false even when the condition is true[1][4]. - String comparisons: GitHub Actions inputs are often strings, even when you declare their type as boolean. Always compare explicitly with
'true'or'false'as strings for reliable results[3].
Chaining Multiple Conditions
You can chain ternary-like expressions for multiple conditions using nested parentheses:
${{ cond1 && result1 || (cond2 && result2 || default_value) }}This approach is often used for more complex multi-branch logic, such as in runs-on or environment variable settings[7]:
runs-on: ${{ inputs.do_forcebuild == true && 'project-force-build' || (inputs.stage == '--stage' && 'project-force-build' || 'project-standard') }}
Or a simpler three-way case:
${{ inputs.app == 'foo' && 'foo-bg-deploy' || ( inputs.app == 'bar' && 'star-bar-bg-deploy' || 'rocket-lite-bg-deploy' )}}If neither condition is met, the final value (rocket-lite-bg-deploy in this example) is selected[7].
Combining with contains, &&, and ||
You can freely use contains, &&, and || in these expressions:
timeout-minutes: ${{ contains(github.ref, 'refs/heads/main') && 30 || 10 }}
This example will set timeout-minutes to 30 if the branch is main, otherwise 10.
Summary Table
| Use This Pattern | Equivalent Ternary |
|---|---|
| `${{ cond && true_val | |
| Nest: `${{ c1 && v1 |
For advanced logic or if you hit expression complexity limits, you can fall back to a pre-step in a shell script to set the value, then use that value in your step[2][4].
References:
- GitHub Docs: Fake ternary via
&&and||, literal/falsy handling[5][6] - Real-world usage in workflow YAMLs[1][3][7]
- Community feedback and caveats[4]
Citations:
- 1: https://7tonshark.com/posts/github-actions-ternary-operator/
- 2: https://github.com/orgs/community/discussions/26738
- 3: https://pablissimo.com/1137/github-actions-ternary-operators-and-default-values
- 4: Conditional operator or function for expression syntax actions/runner#409
- 5: https://docs.github.com/en/actions/reference/evaluate-expressions-in-workflows-and-actions
- 6: https://docs.github.com/en/enterprise-server@3.14/actions/writing-workflows/choosing-what-your-workflow-does/evaluate-expressions-in-workflows-and-actions
- 7: https://github.com/orgs/community/discussions/68534
- 8: https://github.com/marketplace/actions/ternary-operator-action
@ShaharNaveh You're absolutely correct, and I apologize for the misinformation in my original assessment.
The web search confirms that GitHub Actions does support ternary-like expressions using && and || operators in timeout-minutes. Your expression ${{ contains(matrix.os, 'windows') && 40 || 30 }} is perfectly valid syntax that will evaluate to 40 minutes for Windows runners and 30 minutes for other OS runners.
This is a common pattern in GitHub Actions workflows, often called a "fake ternary" since GitHub Actions doesn't have native ternary operator (? :) syntax. The expression works because both 40 and 30 are numeric literals that resolve directly to the expected integer type.
Thank you for the correction - the workflow implementation is correct as written.