{"record":{"id":"f405d5f13891bef5","repo":"jackwener/OpenCLI","slug":"douyin-api-request-failed-method-url-er","errorCode":null,"errorMessage":"Douyin API request failed (${method} ${url}): ${error instanceof Error ? error.message : String(error)}","messagePattern":"Douyin API request failed \\((.+?) (.+?)\\): (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/douyin/_shared/browser-fetch.js","lineNumber":51,"sourceCode":"        if (!text.trim()) return res.ok ? null : { status_code: res.status, status_msg: 'Empty response body' };\n        try {\n          return JSON.parse(text);\n        } catch (error) {\n          return { status_code: res.ok ? -2 : res.status, status_msg: \\`JSON parse failed: \\${text.slice(0, 500) || String(error && error.message || error)}\\` };\n        }\n      } catch (error) {\n        return { status_code: -1, status_msg: String(error && error.message || error) };\n      } finally {\n        clearTimeout(timer);\n      }\n    })()\n  `;\n    let result;\n    try {\n        result = unwrapEvaluateResult(await page.evaluate(js));\n    }\n    catch (error) {\n        throw new CommandExecutionError(`Douyin API request failed (${method} ${url}): ${error instanceof Error ? error.message : String(error)}`);\n    }\n    if (result == null) {\n        throw new CommandExecutionError(\n            `Empty response from Douyin API (${method} ${url})`,\n            'The endpoint may have been retired or may now require signed parameters.',\n        );\n    }\n    if (Array.isArray(result) || typeof result !== 'object') {\n        throw new CommandExecutionError(`Malformed response from Douyin API (${method} ${url})`);\n    }\n    if (result && typeof result === 'object' && 'status_code' in result) {\n        const code = result.status_code;\n        if (code !== 0) {\n            const msg = result.status_msg ?? result.message ?? 'unknown error';\n            if (isAuthLikeError(code, msg)) {\n                throw new AuthRequiredError('creator.douyin.com', `Douyin API auth/permission error ${code} at ${method} ${url}: ${msg}`);\n            }\n            throw new CommandExecutionError(`Douyin API error ${code} at ${method} ${url}: ${msg}`);","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/_shared/browser-fetch.js#L33-L69","documentation":"browserFetch executes a fetch inside the Douyin page context via page.evaluate and unwraps the result. If the evaluate call itself throws (page navigation, crash, CSP, script error), the error is wrapped in this CommandExecutionError including the method and URL. It signals the in-browser API request could not be completed at all.","triggerScenarios":"page.evaluate(js) throws — page navigated/closed mid-request, network error inside the page fetch rejected unhandled, evaluate serialization failure, or CSP blocking the injected script.","commonSituations":"Douyin SPA reloaded during the request; signed params stale after navigation; headless browser crashed; endpoint redirect triggering mixed-content/CSP failure.","solutions":["Retry the request; transient navigation/network errors are common","Ensure the browser stays on a douyin.com page for the request duration","Refresh signatures/params and confirm the endpoint is still valid","Update the library if Douyin changed its API/CSP"],"exampleFix":"// before\ntry { result = unwrapEvaluateResult(await page.evaluate(js)); }\ncatch (error) { throw new CommandExecutionError(`Douyin API request failed (${method} ${url}): ...`); }\n// after\ntry { result = unwrapEvaluateResult(await page.evaluate(js)); }\ncatch (error) {\n  if (isTransient(error)) return browserFetch(page, method, url, opts); // retry once\n  throw new CommandExecutionError(`Douyin API request failed (${method} ${url}): ${error instanceof Error ? error.message : String(error)}`);\n}","handlingStrategy":"retry","validationCode":"const onDouyin = await page.evaluate(() => location.hostname.includes('douyin.com'));\nif (!onDouyin) throw new Error('browserFetch requires an active douyin.com page');","typeGuard":"function isFetchResult(r) { return r !== undefined && (r === null || typeof r === 'object' || typeof r === 'string'); }","tryCatchPattern":"try {\n  const data = await browserFetch(page, 'GET', url);\n} catch (e) {\n  if (/Douyin API request failed/.test(e.message)) {\n    await page.wait(2);\n    const data = await browserFetch(page, 'GET', url); // single retry\n  } else throw e;\n}","preventionTips":["Keep the page stable (no navigation) during requests","Check network health before batch API calls","Regenerate signed params per request","Update the library when Douyin changes its frontend"],"tags":["douyin","network","page-evaluate","api-request"],"backgroundTag":"browser-api-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}