Magic Tools
Developer ToolsBy CooconAugust 5, 202673 views4 min read

GitHub Actions Fails Quickly with Connection Reset: The Cross-Border Pitfall When Overseas Runners Pull Alibaba Cloud ACR

1. Problem Description

A routine push triggered a Docker image build, and GitHub Actions failed directly about 2 seconds after starting:

ERROR: failed to authorize: failed to fetch oauth token:
Post "https://dockerauth.cn-hangzhou.aliyuncs.com/auth": read: connection reset by peer

The log error points to this line in the Dockerfile:

FROM registry.cn-hangzhou.aliyuncs.com/<namespace>/node:22-pm2

The first instinct might go astray: is the base image tag wrong? Has the ACR password expired? Is there a problem with the recently changed Dockerfile?

None of these. The only criterion: with the same Dockerfile and credentials, a previous build succeeded, then one failed, with no related changes in between. The code hasn't changed but the result has, so the problem isn't in the code.

2. Environment

Item Details
CI GitHub Actions, GitHub-hosted runner (overseas data center)
Build docker/build-push-action, multi-platform (amd64 + arm64)
Image Repository Alibaba Cloud ACR (Hangzhou region)
Base Image Custom node:22-pm2, also stored in the same ACR

3. Root Cause

Breaking down the link:

  1. GitHub-hosted runner is overseas.
  2. FROM a private ACR image, buildx needs to fetch an OAuth token from dockerauth.cn-hangzhou.aliyuncs.com during the "load metadata" phase.
  3. This overseas → Alibaba Cloud Hangzhou cross-border TCP link has unstable quality, occasionally being directly RST by intermediate devices—manifesting as connection reset by peer.

So this is an intermittent network-layer failure, not an authentication configuration issue (authentication errors return 401/403 HTTP responses, not TCP connection resets), and certainly not a Dockerfile issue (the error points to the FROM line only because the failure occurs during the metadata parsing stage of that line).

A Diagnostic Mantra Worth Remembering

First, check at which second the failure occurs. Second-level failure = network / authentication link; minute-level failure might be compilation / dependency issue.

Failing in 2 seconds, dependencies haven't even started installing; spending time checking npm packages or code is counterproductive.

4. Fix: Add Automatic Retry in Workflow

The intermittent RST of cross-border links cannot be eliminated from our side, but its characteristic is that retries are likely to succeed. Modify the build step:

- name: Build and push
  id: build
  continue-on-error: true        # 第一次失败不终止 job
  uses: docker/build-push-action@v6
  with:
    context: .
    platforms: linux/amd64,linux/arm64
    push: true
    tags: ${{ env.IMAGE_TAGS }}

- name: Wait before retry
  if: steps.build.outcome == 'failure'
  run: sleep 30                  # 给链路一点恢复时间

- name: Build and push (retry)
  if: steps.build.outcome == 'failure'
  uses: docker/build-push-action@v6
  with:                          # ⚠️ 参数必须与上面逐字一致
    context: .
    platforms: linux/amd64,linux/arm64
    push: true
    tags: ${{ env.IMAGE_TAGS }}

Two practical notes:

  • GitHub Actions YAML does not support anchors (&anchor / *ref), so the with blocks of the two steps cannot be reused; they must be manually kept in verbatim sync—when changing parameters later, both places need to be changed, and it's best to leave comments in the file as reminders.

  • continue-on-error: true will make the step status show a green checkmark when the first step fails (the outer job does not fail), so rely on steps.build.outcome to determine the actual result; don't be fooled by the interface color.

After deploying this retry mechanism, similar intermittent resets are caught by the second build, and there have been no more occurrences of the entire pipeline turning red.

5. Structural Solution (Optional)

Retry is just a stopgap. To make the cross-border dependency of "overseas runners pulling domestic images" disappear entirely, the idea is to mirror the base image to an overseas registry that is stably accessible:

  1. Sync and push a copy of the custom base image to GHCR (ghcr.io)
  2. Change the FROM in Dockerfile to GHCR—pulling side no longer crosses borders
  3. Build artifacts are pushed to ACR as before (push-side cross-border writes are tested to be more stable than authentication pulls, and failures are caught by the retries above)

The cost is maintaining an extra image sync. If the intermittent frequency is not high, the retry solution is sufficient; implement this when the failure frequency affects the release rhythm.

6. Troubleshooting Checklist (Go Through in Order for Similar Errors)

  1. At which second does the failure occur? Second-level → network/authentication direction; minute-level → compilation/dependency direction
  2. Is the error at the TCP layer (connection reset / timeout) or HTTP layer (401/403/404)? The former checks the link, the latter checks credentials
  3. Has the same configuration succeeded before? If it succeeded before and there are no related changes → intermittent environmental issue, retry first
  4. The code line pointed to by the error (e.g., FROM) is just the position being processed at the time of failure, not necessarily an issue with that line

Related Articles

Dev Breakfast · 2026-09-19

Today's headline: The Internal Repo Earned by a Single HEIC Image: OpenAI Forum's SSO Vulnerability. Plus 4 more: ZCode Silently Uploads 313MB Encrypted Package, Keys Only on the Server; Telstra Outage for a Night: One GPS Receiver Sent the National Network Back to 2006; and more.

daily-intelSep 19, 202610 min
23

Dev Breakfast · 2026-09-18

Today's headline: AWS says some data in Middle East facilities can't be recovered: backup is harder than you think. Plus 7 more: Nvidia allows Rust to directly write GPU kernels, with two paths in parallel; 4B model-generated query plans are 81% faster than Postgres; and more.

daily-intelSep 18, 20269 min
48

Service Up, Ports Open, Certs Valid, VPN Dead for 4 Hours: Tailscale Took Over DNS and Left the Proxy Box With No Upstream

A Los Angeles VPS running sing-box (VLESS-REALITY + Hysteria2) lost its VPN the day after Tailscale was installed. systemctl, ports and certificates were all fine. The root cause was in /etc/resolv.conf: Tailscale manages DNS by default, the tailnet had no global nameservers, and when dhclient renewed its lease tailscaled read an empty resolv.conf and dropped its upstream list. From then on every public domain got SERVFAIL, and the REALITY handshake could not even resolve www.apple.com. Full timeline, the evidence for each step, three fixes, and the rules we added to CLAUDE.md so an AI assistant (Claude Code) does not walk into this again.

claude-codetroubleshooting+8
pitfallsSep 17, 20266 min
48

Dev Breakfast · 2026-09-17

Today's headline: Firefox 156 pushes 'Suggest' ads in the address bar, PDF starts up 45% faster. Plus 7 more: Karpathy's autoresearch six months later: Shopify uses it to improve 40+ metrics, rekursiv refreshes nanochat record in three days; Replacing actions/setup-go: Golang CI scaling actual test; and more.

daily-intelSep 17, 20266 min
75

Published by Magic Tools