BigPizzaV3/CodexPlusPlus · warning · Error
上次提交结果尚未确认,请稍后点击继续
Error message
上次提交结果尚未确认,请稍后点击继续
What it means
When resuming a batch whose session is in phase 'submitting' with no turnId, the code searches the side conversation's turns for one whose clientUserMessageId matches session.messageId. If the previously submitted message was never accepted by the backend (no matching turn with a turnId), resume cannot proceed safely and asks the user to click continue later.
Solutions
- Wait a few seconds and click 继续 again — the pending submission may still be registered; if it appears, resume proceeds.
- If it persists, the batch submit is lost: reset the session phase (requestId/turnId cleared) so the batch is resubmitted with a new messageId.
- Check the side conversation in the Codex UI to confirm whether the message actually arrived.
- Reload Codex to refresh turn history, then resume.
Example fix
// before
if(!accepted?.turnId)throw Error('上次提交结果尚未确认,请稍后点击继续');
// after
if(!accepted?.turnId){
if(++resumeAttempts>3){ Object.assign(session,{requestId:null,turnId:null,phase:'ready'});await save(); return resubmit(); }
throw Error('上次提交结果尚未确认,请稍后点击继续');
} Defensive patterns
Strategy: retry
Validate before calling
const accepted = nativeTurns(side).find(t => t.clientUserMessageId === session.messageId); const resumable = Boolean(accepted?.turnId);
Type guard
const hasAcceptedTurn = (side, messageId) => nativeTurns(side).some(t => t.clientUserMessageId === messageId && t.turnId);
Try / catch
try { await nativeSideChat(...); } catch (e) { if (e.message.includes('尚未确认')) { await sleep(5000); retryResume(); } else throw e; } Prevention
- Wait for backend acceptance (turnId present) before persisting phase='submitting'.
- On repeated unconfirmed submits, reset the session so the batch is resubmitted with a new messageId.
- Avoid closing Codex immediately after clicking continue.
When it happens
Trigger: Resuming with session.requestId===requestId && phase==='submitting' && !session.turnId while no turn in nativeTurns(side) has clientUserMessageId===session.messageId — the original submit was lost or not yet persisted.
Common situations: App was closed immediately after clicking continue, before the backend registered the turn; network drop during submission; message id saved but submission silently failed.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/7f6ff8aacb16245d.
Report an issue: GitHub.
Appendix: source
Thrown at tools/conversation-canvas/public/canvas.user.js:592
}
async function nativeSideChat(threadId,prompt,onProgress,signal,options={}){
const {native,scope,manager,parent}=await nativeContext(threadId);
if(typeof native.Mr!=='function'||typeof native.Q1!=='function')throw Error('当前 Codex 版本的后台整理接口尚未适配,请在设置中使用外接 API 整理');
if(!parent?.cwd||parent.sideConversation||parent.ephemeral)throw Error('请在主任务中发起整理');
const session=options.session||{},requestId=options.requestId||'single',save=options.onSession||async function(){};
const hostId=manager.getHostId(),mode=organizerMode();
signal?.throwIfAborted();
let side=session.threadId===threadId&&session.profile===organizerProfile?manager.getConversation(session.sideId):null;
const sameRequest=session.requestId===requestId;
if(!side||(!sameRequest&&(session.batches||0)>=8)){
onProgress('正在准备后台整理 · GPT-5.6 Luna · 中…');
await createOrganizerSide(native,scope,manager,parent,threadId,session,save);
side=manager.getConversation(session.sideId);
}
if(session.sideId===threadId||side?.sideConversation!==true||side?.ephemeral!==true)throw Error('侧边对话隔离检查失败');
if(session.requestId===requestId&&session.phase==='submitting'&&!session.turnId){
const accepted=nativeTurns(side).find(t=>t.clientUserMessageId===session.messageId);
if(!accepted?.turnId)throw Error('上次提交结果尚未确认,请稍后点击继续');
session.turnId=accepted.turnId;session.phase='waiting';await save();
}
if(session.requestId!==requestId||!session.turnId){
signal?.throwIfAborted();
Object.assign(session,{requestId,turnId:null,messageId:crypto.randomUUID(),phase:'submitting'});await save();
session.turnId=await native.Mr({scope,turnTrigger:'side_chat',manager,hostId,targetConversationId:session.sideId,cwd:parent.cwd,agentMode:'auto',permissionProfileId:null,shouldSendPermissionOverrides:false,activeCollaborationMode:mode,clientUserMessageId:session.messageId,
context:{prompt,collaborationMode:mode,workspaceRoots:[parent.cwd],imageAttachments:[],fileAttachments:[],addedFiles:[],commentAttachments:[],selectedTextAttachments:[],pastedTextAttachments:[],threadReferences:[]}});
session.phase='waiting';await save();
}
onProgress('GPT-5.6 Luna · 中 · 正在后台整理,可暂停后继续…');
// No fixed whole-job deadline: retain the turn identity when paused so that
// resume reads the existing response instead of launching duplicate work.
for(;;){
signal?.throwIfAborted();
const conversation=manager.getConversation(session.sideId);
if(!conversation)throw Error('后台整理会话已失效,已完成批次仍保留;点击继续可重新处理本批');
const turn=nativeTurns(conversation).find(t=>t.turnId===session.turnId);
if(turn&&turn.status!=='inProgress'){View on GitHub (pinned to b1ed92e5e4)