fix: patch errorHandling to prevent circular JSON stack overflow

JSON.stringify(err.response.config) in clob-client's errorHandling
includes the httpsAgent (HttpsProxyAgent) object which has circular/deep
refs, causing "Maximum call stack size exceeded" on every API error.

- Fixed live node_modules file to log only status + data (no config)
- Updated patch script to apply this fix idempotently after npm install,
  independent of proxy patch (two separate checks/markers)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
direkturcrypto
2026-04-03 13:32:23 +07:00
co-authored by Claude Sonnet 4.6
parent 49de5c60e9
commit f376b439a5
+48 -46
View File
@@ -32,18 +32,15 @@ if (!fs.existsSync(TARGET)) {
let code = fs.readFileSync(TARGET, 'utf8'); let code = fs.readFileSync(TARGET, 'utf8');
// Check if already patched // Check if proxy support is already patched
if (code.includes('getProxyAgent')) { const proxyAlreadyPatched = code.includes('getProxyAgent');
console.log('[patch] @polymarket/clob-client already patched — skipping'); // Check if the JSON.stringify circular-ref fix is already applied
process.exit(0); const jsonFixAlreadyPatched = !code.includes('config: (_d = err.response)');
}
// ── Inject proxy interceptor after axios import ───────────────────────────── // ── 1. Proxy interceptor ─────────────────────────────────────────────────────
// Instead of patching individual request configs (which causes circular
// reference errors when the config gets serialized), we register an axios
// request interceptor that injects httpsAgent on the fly.
const PATCH_CODE = ` if (!proxyAlreadyPatched) {
const PATCH_CODE = `
// ── Proxy support (auto-patched by scripts/patch-clob-client.cjs) ────────── // ── Proxy support (auto-patched by scripts/patch-clob-client.cjs) ──────────
const https_proxy_agent_1 = require("https-proxy-agent"); const https_proxy_agent_1 = require("https-proxy-agent");
let _cachedProxyAgent = null; let _cachedProxyAgent = null;
@@ -66,47 +63,52 @@ axios_1.default.interceptors.request.use(function(cfg) {
} }
return cfg; return cfg;
}); });
// Safe JSON.stringify that strips circular agent refs
const _safeStringify = (obj) => JSON.stringify(obj, (key, val) => {
if (key === 'httpsAgent' || key === 'httpAgent' || key === 'agent') return undefined;
return val;
});
// ── End proxy patch ──────────────────────────────────────────────────────── // ── End proxy patch ────────────────────────────────────────────────────────
`; `;
const axiosPatterns = [
// Find axios import to inject after — try multiple patterns /tslib_1\.__importDefault\s*\(\s*require\s*\(\s*["']axios["']\s*\)\s*\)\s*;/,
const axiosPatterns = [ /require\s*\(\s*["']axios["']\s*\)\s*;/,
// tslib __importDefault pattern (compiled TS) ];
/tslib_1\.__importDefault\s*\(\s*require\s*\(\s*["']axios["']\s*\)\s*\)\s*;/, let injected = false;
// Standard require for (const pattern of axiosPatterns) {
/require\s*\(\s*["']axios["']\s*\)\s*;/, const match = code.match(pattern);
]; if (match) {
code = code.replace(match[0], match[0] + PATCH_CODE);
let injected = false; console.log('[patch] Injected proxy interceptor after axios import');
for (const pattern of axiosPatterns) { injected = true;
const match = code.match(pattern); break;
if (match) { }
code = code.replace(match[0], match[0] + PATCH_CODE);
console.log(`[patch] Injected proxy interceptor after axios import`);
injected = true;
break;
} }
if (!injected) {
console.error('[patch] Could not find axios import — skipping proxy patch');
}
} else {
console.log('[patch] Proxy support already present — skipping');
} }
if (!injected) { // ── 2. Fix errorHandling circular JSON ───────────────────────────────────────
console.error('[patch] Could not find axios import — skipping'); // JSON.stringify(err.response.config) includes httpsAgent (from proxy) which
console.error('[patch] File content preview (first 1000 chars):'); // has circular/deep refs and causes "Maximum call stack size exceeded".
console.error(code.substring(0, 1000)); // Replace with a simple log that only serializes the response data.
process.exit(0);
}
// ── Patch errorHandling to avoid circular JSON serialization ──────────────── if (!jsonFixAlreadyPatched) {
// The CLOB client does JSON.stringify(err.response.config) which includes const OLD_LOG = `console.error("[CLOB Client] request error", JSON.stringify({
// httpsAgent with circular references. Replace with safe serializer. status: (_a = err.response) === null || _a === void 0 ? void 0 : _a.status,
const jsonCount = (code.match(/JSON\.stringify\(/g) || []).length; statusText: (_b = err.response) === null || _b === void 0 ? void 0 : _b.statusText,
code = code.replace(/JSON\.stringify\(/g, '_safeStringify('); data: (_c = err.response) === null || _c === void 0 ? void 0 : _c.data,
const patchedCount = (code.match(/_safeStringify\(/g) || []).length; config: (_d = err.response) === null || _d === void 0 ? void 0 : _d.config,
console.log(`[patch] Replaced ${jsonCount} JSON.stringify calls with safe serializer`); }));`;
const NEW_LOG = `// config excluded — contains httpsAgent circular refs (stack overflow)
console.error("[CLOB Client] request error:", (_a = err.response) === null || _a === void 0 ? void 0 : _a.status, JSON.stringify((_b = err.response) === null || _b === void 0 ? void 0 : _b.data));`;
if (code.includes(OLD_LOG)) {
code = code.replace(OLD_LOG, NEW_LOG);
console.log('[patch] Fixed errorHandling circular JSON.stringify');
} else {
console.warn('[patch] Could not find errorHandling JSON.stringify — skipping (already fixed or SDK changed)');
}
} else {
console.log('[patch] errorHandling JSON fix already applied — skipping');
}
fs.writeFileSync(TARGET, code, 'utf8'); fs.writeFileSync(TARGET, code, 'utf8');
console.log('[patch] @polymarket/clob-client patched with proxy support ✅'); console.log('[patch] @polymarket/clob-client patched ✅');