{"record":{"id":"d19f71c100f84f48","repo":"jackwener/OpenCLI","slug":"unexpected-12306-probe-json-stringify-probe","errorCode":null,"errorMessage":"Unexpected 12306 probe: ${JSON.stringify(probe)}","messagePattern":"Unexpected 12306 probe: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"warning","filePath":"clis/12306/auth.js","lineNumber":42,"sourceCode":"      }\n      const t = await r.text();\n      let d = null;\n      try { d = JSON.parse(t); } catch {}\n      if (!d || d.status === false || /未登录|登录超时|NotLogin/i.test(t)) {\n        return { kind: 'auth', detail: '12306 initMy12306Api returned NotLogin' };\n      }\n      const userName = d.data?.user_name || d.data?.userName || d.user_name || '';\n      if (!userName) {\n        return { kind: 'auth', detail: '12306 initMy12306Api 200 but no user_name surface' };\n      }\n      return { ok: true, user_name: String(userName) };\n    } catch (e) {\n      return { kind: 'exception', detail: String(e && e.message || e) };\n    }\n  })()`);\n  if (probe?.kind === 'auth') throw new AuthRequiredError('12306.cn', probe.detail);\n  if (probe?.kind === 'exception') throw new CommandExecutionError(`12306 whoami failed: ${probe.detail}`);\n  if (!probe?.ok) throw new CommandExecutionError(`Unexpected 12306 probe: ${JSON.stringify(probe)}`);\n  return { user_name: probe.user_name };\n}\n\nregisterSiteAuthCommands({\n  site: '12306',\n  domain: '12306.cn',\n  loginUrl: 'https://kyfw.12306.cn/otn/resources/login.html',\n  columns: ['user_name'],\n  quickCheck: has12306SessionCookie,\n  verify: verify12306Identity,\n  poll: async (page) => {\n    if (!await has12306SessionCookie(page)) {\n      throw new AuthRequiredError('12306.cn', 'Waiting for 12306 tk auth cookie');\n    }\n    return verify12306Identity(page);\n  },\n});\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/12306/auth.js#L24-L60","documentation":"This TimeoutError is thrown when `twitter bookmark` clicked the bookmark action but could not confirm within 1s that it took effect (result.unconfirmed was true, meaning writeStarted). Since the write may already have happened, retrying blindly could toggle the bookmark off; the CLI surfaces the ambiguity instead of guessing.","triggerScenarios":"The in-page script set writeStarted, clicked the bookmark button, but the post-click state check (aria-pressed/testid) did not flip within 1s — slow render, stale button selector, or the tweet page hadn't fully hydrated.","commonSituations":"Slow connection or heavy DOM on long tweet threads; already-bookmarked tweets where the button state doesn't change; Twitter UI variant A/B tests changing testids; running on a loaded/throttled machine.","solutions":["Open the tweet in the browser and check whether the bookmark icon is already filled before doing anything","If not bookmarked, simply retry the command once","If it was already bookmarked, do nothing — retrying would un-bookmark it","If it recurs, refresh the page and retry; persistent failure suggests a selector change needing a CLI update"],"exampleFix":"// before\nthrow new TimeoutError('twitter bookmark confirmation', 1, `${result.message} ...`);\n// after\nconst isBookmarked = await page.evaluate(`!!document.querySelector('[data-testid=\"bookmark\"][aria-pressed=\"true\"], [data-testid=\"removeBookmark\"]')`);\nif (isBookmarked) return [{ status: 'success', message: 'already bookmarked' }];\n// otherwise retry the bookmark action","handlingStrategy":"retry","validationCode":"const isBookmarked = await page.evaluate(`!!document.querySelector('[data-testid=\"removeBookmark\"]')`);\nif (isBookmarked) return; // already bookmarked — don't retry or you'll un-bookmark","typeGuard":"function isUnconfirmed(r) { return r && typeof r === 'object' && r.unconfirmed === true; }","tryCatchPattern":"try {\n  await opencli('twitter bookmark', url);\n} catch (e) {\n  if (e instanceof TimeoutError && /twitter bookmark confirmation/.test(e.message)) {\n    // check the tweet's bookmark state in the browser before any retry\n  }\n}","preventionTips":["Verify bookmark state before retrying — a blind retry toggles it off","Reload/fully load the tweet page before running","Retry on a warmed-up, fast session","Update the CLI if selector failures persist after UI changes"],"tags":["twitter","timeout","browser-automation","side-effect-confirmation"],"backgroundTag":"side-effect-timeout-unconfirmed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}