BigPizzaV3/CodexPlusPlus · error

历史消息分页游标重复

Error message

历史消息分页游标重复

What it means

Within each turn, readNativeHistory pages thread/items/list tracking used cursors; a repeated itemCursor means the items pagination is looping. The function throws to prevent an infinite fetch cycle. (Note the surrounding code also halves `limit` on 'decoded message length too large' errors.)

Solutions

  1. Upgrade/restart the codex backend to fix items pagination
  2. Test with a smaller turn to isolate whether only oversized turns loop
  3. Inspect the mocked/proxied send('thread/items/list') for a static nextCursor
  4. Report the cursor loop upstream with the threadId/turnId

Example fix

// before
if(cursors.has(itemCursor))throw Error('历史消息分页游标重复');
// after
if(cursors.has(itemCursor)){ console.warn('cursor loop for turn', turn.id); break; } // degrade gracefully
Defensive patterns

Strategy: try-catch

Validate before calling

// no pre-call check; detect loop after response
if (cursors.has(page.nextCursor)) throw new Error('item cursor loop');

Type guard

const isItemsPage = p => p && Array.isArray(p.data);

Try / catch

try { await readNativeHistory(send, threadId) } catch (e) { if (e.message === '历史消息分页游标重复') { usePartialMessagesForTurn(); } else throw e; }

Prevention

When it happens

Trigger: thread/items/list returns a nextCursor equal to a previously used cursor for the same turn, so the do/while would never terminate.

Common situations: Backend bug in per-turn item pagination; huge turns whose cursor handling overflows; proxy/mocked responses with constant cursors; protocol version mismatch.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of BigPizzaV3/CodexPlusPlus@b1ed92e5e4 (2026-09-19). Data as JSON: /api/errors/940fc7f7578d1b2a. Report an issue: GitHub.

Appendix: source

Thrown at tools/conversation-canvas/native-history.mjs:36

    for(const turn of page.data){
      if(typeof turn.id!=='string')throw Error('历史轮次缺少 ID');
      if(!turnIds.has(turn.id)){turnIds.add(turn.id);turns.push(turn);}
    }
    cursor=page.nextCursor??null;
    onProgress(`正在读取轮次目录 · ${turns.length} 轮…`);
  }while(cursor!==null);
  const messages=[],seen=new Set();
  for(const [index,turn] of turns.entries()){
    signal?.throwIfAborted();onProgress(`正在读取历史 ${index+1}/${turns.length}…`);
    const key=`${threadId}:${turn.id}`,cached=await cache.get(key);
    let parsed;
    if(cached&&turn.status==='completed')parsed=cached;
    else{
      const partial=turn.status==='completed'?await cache.get(`${key}:partial`):null;
      parsed=partial?.messages?.slice()||[];let itemCursor=partial?.cursor??null,limit=32;const cursors=new Set();
      do{
        signal?.throwIfAborted();
        if(cursors.has(itemCursor))throw Error('历史消息分页游标重复');
        let page;
        for(;;){
          try{page=await send('thread/items/list',{threadId,turnId:turn.id,cursor:itemCursor,limit,sortDirection:'asc'});break;}
          catch(error){
            if(limit>1&&/decoded message length too large/i.test(error.message)){limit=Math.max(1,Math.floor(limit/2));continue;}
            throw error;
          }
        }
        if(!Array.isArray(page?.data))throw Error('历史消息接口返回格式无效');
        cursors.add(itemCursor);
        for(const row of page.data){
          if(row.turnId!=null&&row.turnId!==turn.id)throw Error('历史消息所属轮次不匹配');
          const item=row.item??row;
          if(!['userMessage','agentMessage'].includes(item.type))continue;
          if(typeof item.id!=='string')throw Error('历史消息缺少稳定 ID');
          const role=item.type==='userMessage'?'user':'assistant';
          const content=role==='user'?(item.content??[]):[{text:item.text??''}];
          const message=parseMessage({type:'response_item',payload:{type:'message',id:item.id,role,phase:role==='assistant'?(item.phase??'final_answer'):'',content}},item.id);

View on GitHub (pinned to b1ed92e5e4)