Note
The bug and fix were generated by my agent. Although it was looked over by me, I am still not 100% confident. Let me know if my logic is wrong and/or there is a different workaround.
Summary
When a reusable workflow (compiled .lock.yml) is called cross-repo via uses: org/repo/.github/workflows/workflow.lock.yml@ref, the "Check workflow lock file" step fails with:
ERR_CONFIG: Lock file 'workflow.lock.yml' is outdated or unverifiable!
Could not verify frontmatter hash for 'workflow.md'.
Run 'gh aw compile' to regenerate the lock file.
The hash check looks for the lock file in the caller's repo instead of the callee's repo, gets a 404, falls back to the local filesystem (also the caller's workspace), and fails.
Root Cause
Two incorrect assumptions in check_workflow_timestamp_api.cjs:
1. ${{ github.workflow_ref }} does NOT resolve to the callee
The compiler (compiler_activation_job.go, line ~227) injects:
GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}"
The comment states:
Unlike the GITHUB_WORKFLOW_REF env var (which always reflects the top-level caller in workflow_call), ${{ github.workflow_ref }} correctly refers to the current reusable workflow being executed.
This is wrong. Per GitHub Actions docs and confirmed via debug output, github.workflow_ref in a reusable workflow returns the caller's workflow ref, not the callee's:
##[debug]Evaluating: github.workflow_ref
##[debug]=> 'caller-org/caller-repo/.github/workflows/caller.yml@refs/heads/main'
The test at line ~800 of check_workflow_timestamp_api.test.cjs encodes this same incorrect assumption:
// Test assumes GH_AW_CONTEXT_WORKFLOW_REF = callee, but GitHub Actions sets it to caller
process.env.GH_AW_CONTEXT_WORKFLOW_REF = "platform-owner/platform-repo/.github/workflows/test.lock.yml@refs/heads/main";
2. referenced_workflows API fallback never fires
The fallback at line ~106 checks if (eventName === "workflow_call"). However, GITHUB_EVENT_NAME inside the reusable workflow appears to be the original trigger event (e.g., push), not workflow_call. The fallback branch never executes — confirmed by the absence of any "workflow_call event detected" log line in the debug output.
What Happens
GH_AW_CONTEXT_WORKFLOW_REF resolves to the caller's workflow → owner/repo parsed as the caller
GITHUB_EVENT_NAME is not workflow_call → referenced_workflows API lookup is skipped
- Hash check fetches lock file from the caller's repo via API → 404
- Falls back to local filesystem (
$GITHUB_WORKSPACE) → also the caller's repo → file not found
- Step fails with
ERR_CONFIG
Reproduction
- Create a reusable workflow in repo A, compile it with
gh aw compile
- In repo B, create a caller workflow that uses it:
jobs:
my-job:
uses: org/repo-a/.github/workflows/workflow.lock.yml@main
secrets:
COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }}
- Trigger repo B's workflow (e.g., push to main)
- The "Check workflow lock file" step fails with
ERR_CONFIG
gh-aw version: v0.67.1
Proposed Fix
The referenced_workflows API approach (lines 105-149) is the right idea but needs to fire for ALL events, not just workflow_call. The fix should:
-
Remove the eventName === "workflow_call" gate — or broaden it to always attempt the referenced_workflows lookup when GH_AW_WORKFLOW_FILE indicates a .lock.yml that might be cross-repo.
-
Fix GH_AW_CONTEXT_WORKFLOW_REF — either stop relying on ${{ github.workflow_ref }} (since it returns the caller) or use a different mechanism. resolve_host_repo.cjs already uses GITHUB_WORKFLOW_REF env var with the comment "GITHUB_WORKFLOW_REF always reflects the currently executing workflow file" — though this also appears to resolve to the caller in practice.
-
Update the test at line ~800 to reflect actual GitHub Actions behavior where both github.workflow_ref and GITHUB_WORKFLOW_REF return the caller's ref in reusable workflows.
Related
Summary
When a reusable workflow (compiled
.lock.yml) is called cross-repo viauses: org/repo/.github/workflows/workflow.lock.yml@ref, the "Check workflow lock file" step fails with:The hash check looks for the lock file in the caller's repo instead of the callee's repo, gets a 404, falls back to the local filesystem (also the caller's workspace), and fails.
Root Cause
Two incorrect assumptions in
check_workflow_timestamp_api.cjs:1.
${{ github.workflow_ref }}does NOT resolve to the calleeThe compiler (
compiler_activation_job.go, line ~227) injects:The comment states:
This is wrong. Per GitHub Actions docs and confirmed via debug output,
github.workflow_refin a reusable workflow returns the caller's workflow ref, not the callee's:The test at line ~800 of
check_workflow_timestamp_api.test.cjsencodes this same incorrect assumption:2.
referenced_workflowsAPI fallback never firesThe fallback at line ~106 checks
if (eventName === "workflow_call"). However,GITHUB_EVENT_NAMEinside the reusable workflow appears to be the original trigger event (e.g.,push), notworkflow_call. The fallback branch never executes — confirmed by the absence of any "workflow_call event detected" log line in the debug output.What Happens
GH_AW_CONTEXT_WORKFLOW_REFresolves to the caller's workflow →owner/repoparsed as the callerGITHUB_EVENT_NAMEis notworkflow_call→referenced_workflowsAPI lookup is skipped$GITHUB_WORKSPACE) → also the caller's repo → file not foundERR_CONFIGReproduction
gh aw compileERR_CONFIGgh-aw version: v0.67.1
Proposed Fix
The
referenced_workflowsAPI approach (lines 105-149) is the right idea but needs to fire for ALL events, not justworkflow_call. The fix should:Remove the
eventName === "workflow_call"gate — or broaden it to always attempt thereferenced_workflowslookup whenGH_AW_WORKFLOW_FILEindicates a.lock.ymlthat might be cross-repo.Fix
GH_AW_CONTEXT_WORKFLOW_REF— either stop relying on${{ github.workflow_ref }}(since it returns the caller) or use a different mechanism.resolve_host_repo.cjsalready usesGITHUB_WORKFLOW_REFenv var with the comment "GITHUB_WORKFLOW_REF always reflects the currently executing workflow file" — though this also appears to resolve to the caller in practice.Update the test at line ~800 to reflect actual GitHub Actions behavior where both
github.workflow_refandGITHUB_WORKFLOW_REFreturn the caller's ref in reusable workflows.Related
GH_AW_CONTEXT_WORKFLOW_REFreferenced_workflowsAPI fallback