Skip to content

engine: claude — get-claude-key.sh missing in chroot (AWF v0.25.4), apiKeyHelper exit 127 #23614

Closed

Description

@virenpepper

Description

Claude engine workflows fail with EHOSTUNREACH because get-claude-key.sh does not exist inside the agent chroot container. The entrypoint correctly writes apiKeyHelper config to both .claude.json and .claude/settings.json (fix from #22713 / gh-aw-firewall#1414 is present), but the script it references (/usr/local/bin/get-claude-key.sh) was never copied into the chroot filesystem. Claude Code falls back to no key and all API calls fail.

Related: This appears to be a regression or incomplete fix from #22713. That issue was closed after AWF v0.25.1 shipped the config path fix, but the script availability inside the chroot was not verified.

Environment

  • gh aw CLI: v0.64.5
  • AWF container image: ghcr.io/github/gh-aw-firewall/agent:0.25.4
  • Claude Code CLI: 2.1.88 (installed at runtime)
  • Repo: private, GitHub Teams plan
  • OS: ubuntu-latest (GitHub-hosted runner)

Steps to Reproduce

  1. Create a Claude engine workflow:
---
on:
  pull_request:
    types: [opened]
  workflow_dispatch:
permissions:
  contents: read
  pull-requests: read
engine: claude
tools:
  github:
    toolsets: [repos, pull_requests]
  mcp: false
network: defaults
safe-outputs:
  add-comment:
    max: 1
---
# Test
Read the PR diff and post a summary as a comment.
  1. Set ANTHROPIC_API_KEY as a repo secret (validated by activation step)
  2. gh aw compile (0 errors, 0 warnings)
  3. Open a PR to trigger the workflow

Expected Behavior

The entrypoint configures apiKeyHelper → get-claude-key.sh resolves the API key through the proxy → Claude Code connects to api.anthropic.com and runs.

Actual Behavior

The entrypoint correctly writes config to both paths (fix from #22713 is present):

[entrypoint] Claude Code API key helper configured: /usr/local/bin/get-claude-key.sh
[entrypoint] ✓ Created /host/home/runner/.claude.json with apiKeyHelper: /usr/local/bin/get-claude-key.sh
[entrypoint] ✓ Created /host/home/runner/.claude/settings.json with apiKeyHelper: /usr/local/bin/get-claude-key.sh
[entrypoint] One-shot token library copied to chroot at /tmp/awf-lib/one-shot-token.so

But the script doesn't exist inside the chroot:

apiKeyHelper failed: exited 127: /bin/sh: 1: /usr/local/bin/get-claude-key.sh: not found

Claude Code reports apiKeySource: "apiKeyHelper" (it found the config) but the helper script fails (exit 127), so no key is obtained. All 10 API retries fail:

{"subtype":"api_retry","attempt":1,"error_status":null,"error":"unknown"}
...
{"subtype":"api_retry","attempt":10,"error_status":null,"error":"unknown"}
{"text":"API Error: Unable to connect to API (EHOSTUNREACH)"}
{"total_cost_usd":0,"input_tokens":0,"output_tokens":0}

Zero tokens consumed, zero cost — the API was never successfully called.

Difference from #22713

Issue #22713 This issue
AWF version 0.25.0 0.25.4
Config written to .claude/settings.json? ❌ No (only .claude.json) ✅ Yes (both files)
apiKeySource at init "none" "apiKeyHelper"
get-claude-key.sh exists in chroot? Unknown ❌ No (exit 127)
Root cause Config path mismatch Script not present in chroot

The #22713 fix resolved the config path issue. This is a different failure: Claude Code now finds the apiKeyHelper config, attempts to call the script, but the script doesn't exist at /usr/local/bin/get-claude-key.sh inside the chroot.

Failed Runs

What I've Tried

  • Upgraded gh-aw from v0.64.4 to v0.64.5 — same failure
  • Removed .mcp.json to eliminate MCP server failures — MCP is now clean, but API key issue persists
  • Set mcp: false in frontmatter — no effect on this issue
  • Confirmed ANTHROPIC_API_KEY is valid (activation step validates: ✅ ANTHROPIC_API_KEY: Configured)
  • API proxy container starts and passes health checks

Activity

  1. locked and limited conversation to collaborators on Mar 31, 2026
  2. unlocked this conversation on Mar 31, 2026
  3. lpcox commented on Mar 31, 2026

    @lpcox
    Collaborator

    🔗 AWF tracking issue: github/gh-aw-firewall#1507

    This was already tracked and fixed: the chroot bind-mounts the host's /usr (read-only) over the container's /usr, hiding the image-resident get-claude-key.sh. The fix (merged in github/gh-aw-firewall#1508) follows the existing one-shot-token.so pattern — copying the script to /host/tmp/awf-lib/ before chroot activation and updating the apiKeyHelper path accordingly.

    Generated by Firewall Issue Dispatcher · ◷

    Generated by Firewall Issue Dispatcher · ◷

  4. virenpepper commented on Mar 31, 2026

    @virenpepper
    Author

    thanks for the quick turnaround on this @lpcox

    i just upgraded to gh-aw v0.65.0 but the compiled lock file still references image-tag 0.25.4. is there an ETA on the next firewall container image release that includes the fix? we're blocked on testing our compliance checker workflow until then

  5. locked and limited conversation to collaborators on Mar 31, 2026
  6. unlocked this conversation on Mar 31, 2026
  7. lpcox commented on Mar 31, 2026

    @lpcox
    Collaborator

    @virenpepper gh-aw v0.65.1 is available now and should have the firewall w/ the PR that fixes your issue. Please ugprade and let me know if you're still having issues. Thanks!

  8. virenpepper commented on Mar 31, 2026

    @virenpepper
    Author

    upgraded to gh-aw v0.65.1 (AWF 0.25.5). progress but still failing:

    what's fixed: the script is now copied to the chroot:

    [entrypoint] Claude key helper copied to chroot at /tmp/awf-lib/get-claude-key.sh
    

    what's still broken: the apiKeyHelper config still points to /usr/local/bin/get-claude-key.sh, not /tmp/awf-lib/get-claude-key.sh:

    [entrypoint] ✓ Created /host/home/runner/.claude/settings.json with apiKeyHelper: /usr/local/bin/get-claude-key.sh
    

    no more exit 127, but all 10 API retry attempts still fail with error: "unknown". zero tokens consumed, EHOSTUNREACH final error. the script exists now but it seems like it's either not being invoked at the right path or it's failing to retrieve the key from the API proxy.

    run: https://github.com/usepepper/salsa/actions/runs/23814978435

  9. locked and limited conversation to collaborators on Mar 31, 2026
  10. unlocked this conversation on Mar 31, 2026
  11. virenpepper commented on Mar 31, 2026

    @virenpepper
    Author

    correction on my previous comment — the logs show the path IS being updated correctly now:

    [entrypoint] ✓ Updated apiKeyHelper path in /host/home/runner/.claude.json
    [entrypoint] ✓ Updated apiKeyHelper path in /host/home/runner/.claude/settings.json
    [entrypoint] Claude key helper copied to chroot at /tmp/awf-lib/get-claude-key.sh
    

    and the firewall allowed 4 requests to api.anthropic.com (0 blocked). so the chroot fix, path fix, and network routing all work.

    but the API calls still fail — error: "unknown", error_status: null, input_tokens: 0, total_cost_usd: 0 for all 10 retries. requests reach anthropic but get rejected.

    this looks like an auth issue: the one-shot token mechanism retrieves something from the API proxy, but whatever it returns isn't accepted by the anthropic API. either the ANTHROPIC_API_KEY isn't being passed correctly through the proxy's token wrapping, or the proxy is returning an invalid/empty token.

    the key works fine outside of gh-aw (validated by the activation step and used directly in other workflows). the issue is specific to the API proxy → one-shot token → claude code CLI chain.

    run: https://github.com/usepepper/salsa/actions/runs/23814978435

  12. locked and limited conversation to collaborators on Mar 31, 2026
  13. unlocked this conversation on Mar 31, 2026
  14. lpcox commented on Mar 31, 2026

    @lpcox
    Collaborator

    @virenpepper thanks, i'll take a look

  15. virenpepper commented on Mar 31, 2026

    @virenpepper
    Author

    is there anything we could do on our end to expedite this process? happy to share logs

  16. lpcox commented on Mar 31, 2026

    @lpcox
    Collaborator

    Having the run link should be enough, but I'll let you know

  17. locked and limited conversation to collaborators on Mar 31, 2026
  18. unlocked this conversation on Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions