Build/Submit details page URL
https://expo.dev/accounts/propertymeld/projects/meldmobile/workflows/019ff80f-2c9e-795b-b6e0-8c6cff5914a1
Summary
EAS Workflows reports jobs that were internally marked SKIPPED (because their if condition evaluated to false) to GitHub as commit status state: success — identical to a job that actually ran and passed. Since GitHub's Commit Status API has no "skipped" state, a skipped job and a genuinely-completed job are visually indistinguishable in the GitHub PR checks list. This is especially misleading around require-approval gates: while a require-approval job is still pending (correctly reported as state: pending), sibling/downstream jobs that get skipped as a side effect can show up as green "✓ success" checks even though they never ran, making a PR look fully deployed/released when it isn't.
Managed or bare?
Bare
Environment
expo-env-info 2.1.0 environment info:
System:
OS: macOS 26.5.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.20.0 - /.nvm/versions/node/v20.20.0/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 11.16.0 - /.nvm/versions/node/v20.20.0/bin/npm
Watchman: 2026.01.12.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 25.5, iOS 26.5, macOS 26.5, tvOS 26.5, visionOS 26.5, watchOS 26.5
IDEs:
Android Studio: 2026.1 AI-261.23567.138.2611.15646644
Xcode: 26.5/17F42 - /usr/bin/xcodebuild
npmPackages:
expo: ~54.0.34 => 54.0.34
expo-router: ~6.0.23 => 6.0.23
expo-updates: ~29.0.17 => 29.0.17
react: 19.1.0 => 19.1.0
react-dom: 19.1.0 => 19.1.0
react-native: 0.81.5 => 0.81.5
react-native-web: ~0.21.2 => 0.21.2
npmGlobalPackages:
eas-cli: 21.8.0
Expo Workflow: bare
Error output
Not applicable — this is not a crash/error, but a status-reporting inconsistency between EAS's internal job state and the GitHub commit status it publishes.
Reproducible demo or steps to reproduce from a blank project
- Create an EAS Workflow with:
- a
require-approval job (e.g. approval_gate),
- a second, independent job whose
if condition is only true when a build already exists (e.g. if: ${{ needs.get_ios_build.outputs.build_id || needs.get_android_build.outputs.build_id }}), plus one or more jobs after it (e.g. two update-type jobs that publish an OTA update once that job succeeds).
- Trigger the workflow on a commit where no existing build matches the current fingerprint, so the conditional branch's
if evaluates to false and those jobs are marked SKIPPED by EAS, while approval_gate is left ACTION_REQUIRED (pending human approval).
- Compare EAS's own record of job state against what's published to GitHub for the same commit:
eas workflow:view <run-id> --json → the skipped jobs show "status": "SKIPPED".
gh api repos/{owner}/{repo}/commits/{sha}/statuses (or the PR's checks list in the GitHub UI) → the same jobs show "state": "success" (with "description": "Job has been skipped.").
- Expected: a job EAS itself considers
SKIPPED should not be reported to GitHub as success, since that's indistinguishable from a job that actually ran and passed. Actual: it's reported as success.
Example observed in one of our production workflow runs (details anonymized):
| Job (role) |
EAS status (eas workflow:view) |
GitHub commit status |
| conditional approval gate, skipped because no build existed yet |
SKIPPED |
state: success, "Job has been skipped." |
| downstream update-publish job (Android) |
SKIPPED |
state: success, "Job has been skipped." |
| downstream update-publish job (iOS) |
SKIPPED |
state: success, "Job has been skipped." |
primary require-approval gate, awaiting a human click |
ACTION_REQUIRED |
state: pending, "Job requires user action." (correct) |
Build/Submit details page URL
https://expo.dev/accounts/propertymeld/projects/meldmobile/workflows/019ff80f-2c9e-795b-b6e0-8c6cff5914a1
Summary
EAS Workflows reports jobs that were internally marked SKIPPED (because their if condition evaluated to false) to GitHub as commit status state: success — identical to a job that actually ran and passed. Since GitHub's Commit Status API has no "skipped" state, a skipped job and a genuinely-completed job are visually indistinguishable in the GitHub PR checks list. This is especially misleading around require-approval gates: while a require-approval job is still pending (correctly reported as state: pending), sibling/downstream jobs that get skipped as a side effect can show up as green "✓ success" checks even though they never ran, making a PR look fully deployed/released when it isn't.
Managed or bare?
Bare
Environment
expo-env-info 2.1.0 environment info:
System:
OS: macOS 26.5.1
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.20.0 - /.nvm/versions/node/v20.20.0/bin/node
Yarn: 1.22.22 - /opt/homebrew/bin/yarn
npm: 11.16.0 - /.nvm/versions/node/v20.20.0/bin/npm
Watchman: 2026.01.12.00 - /opt/homebrew/bin/watchman
Managers:
CocoaPods: 1.16.2 - /opt/homebrew/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 25.5, iOS 26.5, macOS 26.5, tvOS 26.5, visionOS 26.5, watchOS 26.5
IDEs:
Android Studio: 2026.1 AI-261.23567.138.2611.15646644
Xcode: 26.5/17F42 - /usr/bin/xcodebuild
npmPackages:
expo: ~54.0.34 => 54.0.34
expo-router: ~6.0.23 => 6.0.23
expo-updates: ~29.0.17 => 29.0.17
react: 19.1.0 => 19.1.0
react-dom: 19.1.0 => 19.1.0
react-native: 0.81.5 => 0.81.5
react-native-web: ~0.21.2 => 0.21.2
npmGlobalPackages:
eas-cli: 21.8.0
Expo Workflow: bare
Error output
Not applicable — this is not a crash/error, but a status-reporting inconsistency between EAS's internal job state and the GitHub commit status it publishes.
Reproducible demo or steps to reproduce from a blank project
require-approvaljob (e.g.approval_gate),ifcondition is only true when a build already exists (e.g.if: ${{ needs.get_ios_build.outputs.build_id || needs.get_android_build.outputs.build_id }}), plus one or more jobs after it (e.g. twoupdate-type jobs that publish an OTA update once that job succeeds).ifevaluates tofalseand those jobs are markedSKIPPEDby EAS, whileapproval_gateis leftACTION_REQUIRED(pending human approval).eas workflow:view <run-id> --json→ the skipped jobs show"status": "SKIPPED".gh api repos/{owner}/{repo}/commits/{sha}/statuses(or the PR's checks list in the GitHub UI) → the same jobs show"state": "success"(with"description": "Job has been skipped.").SKIPPEDshould not be reported to GitHub assuccess, since that's indistinguishable from a job that actually ran and passed. Actual: it's reported assuccess.Example observed in one of our production workflow runs (details anonymized):
eas workflow:view)SKIPPEDstate: success, "Job has been skipped."SKIPPEDstate: success, "Job has been skipped."SKIPPEDstate: success, "Job has been skipped."require-approvalgate, awaiting a human clickACTION_REQUIREDstate: pending, "Job requires user action." (correct)