google/zx · error · Fail
Failed to fetch remote script: ${remote} (${res.status})
Error message
Failed to fetch remote script: ${remote} (${res.status}) What it means
Thrown by readScriptFromHttp() when `zx <http(s) url>` gets a non-2xx response. zx fetches the URL with the global fetch() and rejects on !res.ok, embedding the HTTP status code in the message and setting exitCode to 1.
Source
Thrown at src/cli.ts:256
if (ext === '.md') {
script = transformMarkdown(script)
tempPath = getFilepath(dir, base, EXT)
}
if (argSlice) updateArgv(argv._.slice(argSlice))
return { script, scriptPath, tempPath }
}
async function readScriptFromStdin(): Promise<string> {
return process.stdin.isTTY ? '' : stdin()
}
async function readScriptFromHttp(remote: string): Promise<string> {
const res = await fetch(remote)
if (!res.ok) {
console.error(`Error: Can't get ${remote}`)
process.exitCode = 1
throw new Fail(`Failed to fetch remote script: ${remote} (${res.status})`)
}
return res.text()
}
export function injectGlobalRequire(origin: string): void {
const __filename = path.resolve(origin)
const __dirname = path.dirname(__filename)
const require = createRequire(origin)
Object.assign(globalThis, { __filename, __dirname, require })
}
export function isMain(
meta: ImportMeta['url'] | ImportMeta = import.meta.url,
scriptpath: string = process.argv[1]
): boolean {
if (typeof meta === 'string') {
if (meta.startsWith('file:')) {
const modulePath = url.fileURLToPath(meta).replace(/\.\w+$/, '')View on GitHub (pinned to 00a2c484e2)
Solutions
- Verify the URL independently: `curl -iL <url>` and check the status.
- Use the raw URL for gists/repos (e.g. `https://raw.githubusercontent.com/...`).
- Add authentication (token in the URL or a custom fetch via a wrapper) if the resource is private.
- Download the file and run it locally instead: `curl -o s.mjs <url> && zx s.mjs`.
- Retry; if flaky, wrap the zx invocation in a retry or check connectivity/proxy.
Example fix
// before: gist HTML page is not the script $ zx https://gist.github.com/user/abc123 // after: use the raw endpoint $ zx https://raw.githubusercontent.com/gist/abc123/raw/script.mjs
Defensive patterns
Strategy: retry
Validate before calling
async function headOk(url: string): Promise<boolean> {
const res = await fetch(url, { method: 'HEAD' })
return res.ok
}
if (!(await headOk(scriptUrl))) {
throw new Error(`remote script unreachable: ${scriptUrl}`)
} Try / catch
try {
await runRemote(scriptUrl)
} catch (e) {
if (e instanceof Fail && /Failed to fetch remote script/.test(e.message)) {
// fall back: download then run locally
await $`curl -fsSL ${scriptUrl} -o /tmp/s.mjs`
await $`zx /tmp/s.mjs`
} else throw e
} Prevention
- Verify remote URLs with curl -iL before wiring them into zx invocations.
- Pin to raw content URLs (raw.githubusercontent.com) for gists and repo files.
- Cache remote scripts locally for offline/retry resilience instead of fetching on every run.
When it happens
Trigger: `zx https://example.com/script.mjs` where the server returns 404/403/500; a gist URL that is not the raw endpoint (HTML page, non-2xx); a private repo/gist requiring auth; corporate proxy returning a block page (403).
Common situations: Wrong or mistyped URL; deleted/moved remote script; auth required; corporate proxy/VPN interfering; transient server outage.
Related errors
- Can't link node_modules: ${target} doesn't exist or is not a
- Can't link node_modules: ${alias} already exists
- No script provided
AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13).
Data as JSON: /api/errors/b8c805003627d6f9.
Report an issue: GitHub.