BigPizzaV3/CodexPlusPlus · error
待恢复批次与资料不匹配
Error message
待恢复批次与资料不匹配
What it means
organizeLong resumes a possibly-persisted job. When a pending batch exists it maps pending.partIds through partIndex (current history parts); if any partId no longer resolves to a part, the saved batch no longer matches the conversation material and resuming is refused rather than producing corrupt output.
Solutions
- Restart organizeLong from the current history (drop the stale pending batch)
- Verify the saved document corresponds to the same thread/history snapshot
- Clear job.pending and let nextBatch recompute from done state if the parts changed
- Re-run from scratch; completed batches in state.done may still be reusable
Example fix
// before await organizeLong(resumedDocument) // stale pending partIds // after resumedDocument.job.pending = null; // recompute batch from current parts await organizeLong(resumedDocument)
Defensive patterns
Strategy: validation
Validate before calling
const idx = new Map(history.parts.map(p => [p.partId, p]));
const stale = (job.pending?.partIds || []).filter(id => !idx.has(id));
if (stale.length) throw new Error('stale pending parts: ' + stale.join(',')); Try / catch
try { await organizeLong(doc) } catch (e) { if (e.message === '待恢复批次与资料不匹配') { doc.job.pending = null; restartJob(); } else throw e; } Prevention
- Never edit thread messages while an organization run is paused
- Persist history snapshot together with job state
- Clear job.pending when parts change
- Use the same thread content for resume as for the original run
When it happens
Trigger: Resuming a saved document whose job.pending.partIds reference parts that were removed/changed in history.parts (conversation edited or reloaded from a different history snapshot).
Common situations: Editing/deleting messages in the native thread while a long-organization run is paused; restoring an old checkpoint file against newer history; mismatched thread content between sessions.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19).
Data as JSON: /api/errors/ef048726ec1c10f4.
Report an issue: GitHub.
Appendix: source
Thrown at tools/conversation-canvas/long-organizer.mjs:126
// coverage; a restart can resume its pending side-chat turn before resubmitting.
export async function organizeLong({messages,record,save,run,signal,progress=()=>{},onGraph=()=>{},compact=false}){
const history=await prepareHistory(messages,signal);
const partIndex=new Map(history.parts.map(part=>[part.partId,part]));
const previous=record?.published;
let job=record?.job;
if(!job||!compatible(job.state.manifest,history.manifest)){
const incremental=previous?.done&&compatible(previous.manifest,history.manifest);
const state=incremental?{...previous,manifest:history.manifest}:{schemaVersion:2,nodes:[],currentNodeId:null,batchCount:0,done:{},manifest:history.manifest};
job={kind:incremental||!previous?.nodes?.length?'incremental':'rebuild',state,session:{},pending:null};
}else job={...job,state:{...job.state,manifest:history.manifest}};
let document={version:3,published:previous??null,job};
const persist=async()=>{signal?.throwIfAborted();await save(structuredClone(document));};
await persist();
for(;;){
signal?.throwIfAborted();
// A resumed final batch must not absorb messages appended while paused.
const batch=job.pending?job.pending.partIds.map(id=>partIndex.get(id)):nextBatch(history.parts,job.state.done);
if(batch.some(part=>!part))throw Error('待恢复批次与资料不匹配');
if(!batch.length)break;
progress(`正在整理第 ${job.state.batchCount+1} 批 · 已处理 ${Object.keys(job.state.done).length}/${history.parts.length} 个片段`);
if(!job.pending){job.pending={requestId:crypto.randomUUID(),partIds:batch.map(p=>p.partId),compact};await persist();}
if(JSON.stringify(job.pending.partIds)!==JSON.stringify(batch.map(p=>p.partId)))throw Error('待恢复批次与资料不匹配');
const {requestId}=job.pending,{catalog,prefix,aliases,prompt:basePrompt}=batchPrompt(batch,job.state,requestId,job.pending.compact);
const repair=job.pending.repair;
const missing=repair?.missingPartIds?.map(id=>aliases?Object.keys(aliases).find(key=>aliases[key]===id)||id:id);
const prompt=basePrompt+(repair?`\n上次回复未通过覆盖校验,未保存任何本批节点。本次为第 ${repair.attempt}/2 次补正。上次漏引的 partId:${JSON.stringify(missing)}。请重新输出整个批次的完整 JSON,使用本次 requestId,覆盖本批全部 ${batch.length} 个片段(包括上次已引用的片段),不要只输出遗漏部分。发送前逐个核对 sources;重复讨论、进度说明也要归入有依据的任务节点。`: '');
const response=await run(prompt,requestId,job.session,async()=>save(structuredClone(document)));
signal?.throwIfAborted();
let next;
try{next=mergeBatch(response,job.state,batch,requestId,catalog,prefix,aliases);}
catch(error){
job.session.turnId=null;job.session.requestId=null;
if(error.missingPartIds&&(repair?.attempt||0)<2){
job.pending={requestId:crypto.randomUUID(),partIds:batch.map(p=>p.partId),compact:job.pending.compact,repair:{attempt:(repair?.attempt||0)+1,missingPartIds:error.missingPartIds}};
await persist();progress(`本批遗漏 ${error.missingPartIds.length} 个片段,正在自动补正 ${job.pending.repair.attempt}/2…`);continue;
}View on GitHub (pinned to b1ed92e5e4)