BigPizzaV3/CodexPlusPlus · error · Error
Codex++ 会话接口尚未连接,请稍后点击刷新
Error message
Codex++ 会话接口尚未连接,请稍后点击刷新
What it means
readCanvasSource in the userscript first tries the injected Codex++ bridge window.__codexSessionDeleteBridge to export a session. If that global function does not exist (the Codex++ extension has not injected its bridge into the page yet), it throws this message telling the user the session API isn't connected and to click refresh later.
Solutions
- Wait a moment and click the canvas refresh button so readCanvasSource retries after the bridge is injected
- Verify the Codex++ extension is installed and enabled for the Codex site
- Reload the Codex page to force bridge re-injection
- Update the userscript/extension to matching versions if Codex UI changed
Example fix
// before
if(typeof window.__codexSessionDeleteBridge!=='function')throw Error('Codex++ 会话接口尚未连接,请稍后点击刷新');
// after
if(typeof window.__codexSessionDeleteBridge!=='function'){await new Promise(r=>setTimeout(r,1500));}
if(typeof window.__codexSessionDeleteBridge!=='function')throw Error('Codex++ 会话接口尚未连接,请稍后点击刷新'); Defensive patterns
Strategy: retry
Validate before calling
function bridgeReady(){return typeof window.__codexSessionDeleteBridge==='function';} Type guard
const hasBridge = (w)=>typeof w!=='undefined' && typeof w.__codexSessionDeleteBridge==='function';
Try / catch
try{await readCanvasSource(id,signal,progress);}catch(e){if(e.message.includes('尚未连接')){await new Promise(r=>setTimeout(r,1500));/* retry once */}else throw e;} Prevention
- Delay canvas init until window load plus a short grace period
- Poll for the bridge global before enabling session-dependent UI
- Keep extension and userscript versions in sync
When it happens
Trigger: Calling readCanvasSource (e.g. via canvas load/refresh) while window.__codexSessionDeleteBridge is undefined or not a function — the userscript ran before the Codex++ bridge was injected, or the bridge was never injected on this page/frame.
Common situations: Page just loaded and canvas script executes before the extension content script; Codex++ extension disabled/not installed; bridge injection failed after a Codex web app update changed the injection point; canvas opened in an iframe without the bridge.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/b38c6a407d1328c3.
Report an issue: GitHub.
Appendix: source
Thrown at tools/conversation-canvas/public/canvas.user.js:1141
const needle=normalize(message.text).slice(0,100);
if(needle.length>=15){
const candidates=[...document.querySelectorAll('p,pre,[data-message-id],article')].filter(e=>!host.contains(e)&&normalize(e.textContent).includes(needle));
const leaves=candidates.filter(e=>!candidates.some(other=>other!==e&&e.contains(other)));
if(leaves.length===1)target=leaves[0];
}
}
if(!target){$('jump-status').textContent=({revealed:'已展开所属轮次,但该消息仍被折叠或未显示。可先查看对应原文。',unavailable:'当前页面的历史定位尚未就绪。可先查看对应原文。','missing-turn':'该来源缺少轮次信息。可先查看对应原文。',failed:'原聊天轮次展开失败。可先查看对应原文。'})[navigationState];return;}
closePanel();
target.scrollIntoView({behavior:'smooth',block:'center'});
target.animate([{outline:'2px solid #888',backgroundColor:'#8882'},{outline:'2px solid transparent',backgroundColor:'transparent'}],{duration:2000});
$('jump-status').textContent='正在定位原聊天消息…';
setTimeout(()=>{if(disposed||currentId()!==threadId)return;const r=target.getBoundingClientRect();$('jump-status').textContent=target.isConnected&&r.height>0&&r.bottom>0&&r.top<innerHeight?'已定位并高亮原聊天消息。':'消息已找到,滚动尚未完成。';},700);
}
async function readCanvasSource(id,signal,progress){
if(!nativeReadTasks.has(id)){
let result;
try{
if(typeof window.__codexSessionDeleteBridge!=='function')throw Error('Codex++ 会话接口尚未连接,请稍后点击刷新');
let timer;
try{result=await Promise.race([window.__codexSessionDeleteBridge('/session/export',{session_id:id}),new Promise((_,reject)=>{timer=setTimeout(()=>reject(Error('会话读取超时,请重试')),15000);})]);}
finally{clearTimeout(timer);}
}catch(error){if(!isExportSizeError(error.message))throw error;result={message:error.message};}
if(result?.status==='ok')return result;
if(!isExportSizeError(result?.message))throw Error(result?.message||'Codex++ 会话读取失败');
nativeReadTasks.add(id);
}
signal.throwIfAborted();progress('会话较大,正在改用原生分页读取…');
const {manager}=await nativeContext(id);
const messages=await readNativeHistory((method,params)=>manager.sendRequest(method,params,{priority:'background',timeoutMs:15000}),id,historyCache,progress,signal);
const signature=[];for(const message of messages){signal.throwIfAborted();signature.push(message.id+':'+await messageDigest(message));}
return {status:'ok',kind:'canvas-messages',session_id:id,messages,content:signature.join('|')};
}
async function sync(force=false){
const id=currentId();
if(!id){historyAbort?.abort();requestSequence++;active='';pending=null;data=null;revision='';taskCanvas.context('');$('pending-tray').replaceChildren();$('transcript').replaceChildren();$('details').hidden=true;status('请打开具体任务。');return;}
if(id!==active){View on GitHub (pinned to b1ed92e5e4)