slopus/happy · error
Proxy error
Error message
Proxy error
What it means
startHTTPDirectProxy wraps an http-proxy instance targeting `options.target`. When http-proxy emits its 'error' event — the upstream target is unreachable, DNS fails, the connection is refused/timed out, TLS verification fails, or the socket errors mid-request — the handler logs the cause and, if the client response hasn't already sent headers, replies HTTP 500 with the body 'Proxy error'.
Source
Thrown at packages/happy-cli/src/modules/proxy/startHTTPDirectProxy.ts:25
verbose?: boolean;
onRequest?: (req: IncomingMessage, proxyReq: ClientRequest) => void;
onResponse?: (req: IncomingMessage, proxyRes: IncomingMessage) => void;
}
export async function startHTTPDirectProxy(options: HTTPProxyOptions) {
const proxy = httpProxy.createProxyServer({
target: options.target,
changeOrigin: true,
secure: false
});
let requestId = 0;
// Handle proxy errors
proxy.on('error', (err, req, res) => {
logger.debug(`[HTTPProxy] Proxy error: ${err.message} for ${req.method} ${req.url}`);
if (res instanceof ServerResponse && !res.headersSent) {
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('Proxy error');
}
});
// Trace outgoing proxy requests
proxy.on('proxyReq', (proxyReq, req, res) => {
// const id = ++requestId;
// (req as any)._proxyRequestId = id;
// logger.debug(`[HTTPProxy] [${id}] --> ${req.method} ${req.url}`);
// if (options.verbose) {
// logger.debug(`[HTTPProxy] [${id}] --> Target: ${options.target}${req.url}`);
// logger.debug(`[HTTPProxy] [${id}] --> Headers: ${JSON.stringify(req.headers)}`);
// }
// Allow custom request handler
if (options.onRequest) {
options.onRequest(req, proxyReq);View on GitHub (pinned to b824cd0a46)
Solutions
- Confirm the upstream `target` is running and reachable: `curl <target>` from the same machine; start/restart the target service if it's down.
- Check the CLI file logs for '[HTTPProxy] Proxy error: ...' to see the underlying errno (ECONNREFUSED, ECONNRESET, ENOTFOUND, EPROTO) and fix accordingly.
- Correct the `target` option (host:port/protocol) passed to startHTTPDirectProxy.
- If ECONNRESET happens on long requests, disable upstream keep-alive/agent reuse or increase target server timeouts; retry the failed request.
Example fix
// before: proxy points at a dead upstream
await startHTTPDirectProxy({ target: 'http://127.0.0.1:3000' }); // nothing listening → 500 Proxy error
// after: verify/start target first, then proxy
await fetch('http://127.0.0.1:3000/health'); // ensure reachable
await startHTTPDirectProxy({ target: 'http://127.0.0.1:3000' }); Defensive patterns
Strategy: try-catch
Validate before calling
// Before starting the proxy, verify the upstream target answers
const target = 'http://127.0.0.1:3000';
await fetch(target, { method: 'HEAD' }).catch((e) => {
throw new Error(`Upstream ${target} unreachable (${e.cause?.code ?? e.message}) — start it before proxying`);
}); Type guard
function isProxyErrorBody(body: unknown): body is { error: 'Proxy error' } {
return typeof body === 'object' && body !== null &&
(body as any).error === 'Proxy error';
} Try / catch
// On the client side of the proxy, detect the 500 'Proxy error' response and inspect logs
const res = await fetch(urlThroughProxy);
if (res.status === 500 && (await res.text()).includes('Proxy error')) {
// upstream failed: check '[HTTPProxy] Proxy error:' in CLI logs for ECONNREFUSED/ECONNRESET,
// then retry after confirming the target service is up
} Prevention
- Always confirm the upstream target service is running and healthy before starting the proxy.
- Double-check the `target` host/port/protocol passed to startHTTPDirectProxy.
- Watch for ECONNRESET on long/streaming requests — adjust target keep-alive/timeouts.
- Enable the proxy's verbose/log output so the underlying errno is captured when a 500 'Proxy error' appears.
When it happens
Trigger: Any request forwarded through the proxy when the upstream `target` cannot be reached or errors: target server down, wrong target host/port, ECONNRESET from the upstream, target closing keep-alive sockets, or HTTPS certificate failures (proxy created with secure:false reduces but does not eliminate TLS errors).
Common situations: Local dev server not started (or crashed) while the proxy points at it; wrong `target` port in configuration; target restarted and in-flight keep-alive connections got reset; firewall/DNS blocking the target host; target killing long-running requests (streaming/SSE) mid-flight.
Related errors
- Authentication failed
- Server unavailable
- Token exchange failed: ${tokenResponse.statusText}
- Token exchange failed: ${error}
- Token exchange failed: ${error}
AI-assisted analysis of slopus/happy@b824cd0a46 (2026-08-31).
Data as JSON: /api/errors/0a1a1875bbafa46f.
Report an issue: GitHub.