{"record":{"id":"59395a0fd7f3b3f9","repo":"jackwener/OpenCLI","slug":"douyin-search-evaluator-returned-malformed-cards","errorCode":null,"errorMessage":"Douyin search: evaluator returned malformed cards payload","messagePattern":"Douyin search: evaluator returned malformed cards payload","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/douyin/search.js","lineNumber":294,"sourceCode":"            throw new CommandExecutionError(`Douyin search extraction failed: ${error instanceof Error ? error.message : String(error)}`);\n        }\n        if (!result || typeof result !== 'object') {\n            throw new CommandExecutionError('Douyin search: unexpected evaluator payload shape');\n        }\n        if (result.state === 'login_wall') {\n            throw new AuthRequiredError(\n                'www.douyin.com',\n                'Douyin search results are blocked behind a login wall — log in at https://www.douyin.com in Chrome first.',\n            );\n        }\n        if (result.state === 'empty') {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        if (result.state === 'timeout') {\n            throw new CommandExecutionError('Douyin search did not render result cards within the timeout. Open the same search in Chrome and verify login/security state before retrying.');\n        }\n        if (!Array.isArray(result.cards)) {\n            throw new CommandExecutionError('Douyin search: evaluator returned malformed cards payload');\n        }\n        if (result.cards.length === 0) {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        const projected = projectSearchCards(result.cards, limit);\n        if (projected.invalidCount > 0) {\n            throw new CommandExecutionError('Douyin search parser found result cards without stable video url or description');\n        }\n        if (projected.rows.length === 0) {\n            throw new EmptyResultError('douyin search', `No Douyin videos matched \"${keyword}\".`);\n        }\n        return projected.rows;\n    },\n});\n","sourceCodeStart":276,"sourceCodeEnd":309,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/douyin/search.js#L276-L309","documentation":"CommandExecutionError thrown when the evaluator returned an object with a valid state (e.g. 'ok') but result.cards is not an array. This indicates the in-page extraction script and the Node-side contract have drifted — the payload shape changed between the browser script and the adapter's validation.","triggerScenarios":"WAIT_AND_EXTRACT_JS updated to return cards as an object/null while search.js still expects an array; an intermediate wrapper (unwrapEvaluateResult) reshaped the payload; a modified/older version of one side is loaded.","commonSituations":"Partial upgrade where the page-injected JS is cached in Chrome but the CLI is new (or vice versa); local edits to the evaluator script; mixed-version opencli installation.","solutions":["Reload the bridge/extension and retry so the injected evaluator matches the CLI version.","Ensure opencli and the adapter file are the same version (reinstall/upgrade fully).","Diff WAIT_AND_EXTRACT_JS's return contract against this check and align them.","Log JSON.stringify(result) to inspect the actual shape before fixing either side."],"exampleFix":"// before\nif (!Array.isArray(result.cards)) {\n    throw new CommandExecutionError('Douyin search: evaluator returned malformed cards payload');\n}\n// after\nconst cards = result.cards ?? result.data?.cards;\nif (!Array.isArray(cards)) {\n    throw new CommandExecutionError(`Douyin search: malformed cards payload: ${JSON.stringify(result).slice(0, 300)}`);\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"function hasCardsArray(result) {\n  return result != null && typeof result === 'object' && Array.isArray(result.cards);\n}","tryCatchPattern":"try {\n  rows = await douyinSearch(keyword);\n} catch (e) {\n  if (/malformed cards payload/.test(e.message)) {\n    console.error('Evaluator/CLI version drift — reload the bridge extension and retry');\n  }\n  throw e;\n}","preventionTips":["Upgrade the CLI and browser bridge together; avoid mixed versions.","Pin a contract test asserting WAIT_AND_EXTRACT_JS returns {state: string, cards: Array}.","Hard-refresh the bridged page so the injected evaluator is not stale."],"tags":["payload-shape","version-mismatch","douyin"],"backgroundTag":"evaluator-payload-shape-mismatch","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}