{"record":{"id":"14d351b24d6b16db","repo":"BigPizzaV3/CodexPlusPlus","slug":"organize-14d351","errorCode":null,"errorMessage":"当前推进节点不存在","messagePattern":"当前推进节点不存在","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/conversation-canvas/organize.mjs","lineNumber":36,"sourceCode":"    for(const key of ['title','summary','description','status'])if(typeof n[key]!=='string'||!n[key].trim()||n[key].length>12000)throw Error('整理结果缺少节点描述');\n    if(n.parent!==null&&typeof n.parent!=='string')throw Error('整理结果父节点无效');\n    ids.add(n.id);nodes.push({id:n.id,parent:n.parent,lane:n.lane,title:n.title,summary:n.summary,description:n.description,status:n.status,sources:[...new Set(n.sources)]});\n  }\n  const roots=nodes.filter(n=>n.parent===null),byId=new Map(nodes.map(n=>[n.id,n]));\n  if(roots.length!==1||roots[0].lane!=='main')throw Error('任务树必须有且只有一个主目标根节点');\n  const checked=new Set();\n  for(const node of nodes){\n    const path=new Set();let current=node;\n    while(current&&!checked.has(current.id)){\n      if(path.has(current.id))throw Error('任务树存在循环关联');\n      path.add(current.id);\n      if(current.parent!==null&&!byId.has(current.parent))throw Error('任务树包含不存在的父节点');\n      current=current.parent===null?null:byId.get(current.parent);\n    }\n    for(const id of path)checked.add(id);\n  }\n  const currentNodeId=value.currentNodeId??null;\n  if(currentNodeId!==null&&!byId.has(currentNodeId))throw Error('当前推进节点不存在');\n  return {schemaVersion:2,currentNodeId,nodes};\n}\n\nexport function parseOrganization(text,messages,requestId) {\n  const blocks=[...text.matchAll(/```(?:json)?\\s*([\\s\\S]*?)```/g)].map(m=>m[1]);\n  for(const raw of [...blocks,text.trim()]){\n    let value;try{value=JSON.parse(raw);}catch{continue;}\n    if(value?.requestId===requestId)return validateOrganization(value,messages,requestId);\n  }\n  throw Error('侧边对话未返回可识别的整理结果');\n}\n","sourceCodeStart":18,"sourceCodeEnd":48,"githubUrl":"https://github.com/BigPizzaV3/CodexPlusPlus/blob/b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6/tools/conversation-canvas/organize.mjs#L18-L48","documentation":"The organization result carries an optional `currentNodeId` marking which node is currently in progress; it defaults to null when absent. If provided, it must match one of the validated node ids; otherwise the validator throws because the pointer would reference a nonexistent node.","triggerScenarios":"The model returns {\"currentNodeId\":\"n42\",...} while nodes only contain other ids; the id casing or prefix differs (\"N1\" vs \"n1\"); currentNodeId points at a node removed in a later revision while the pointer was stale. Check: `currentNodeId!==null&&!byId.has(currentNodeId)`.","commonSituations":"Model hallucinates a current node id not in its own list; the id numbering restarted mid-response; an edited/trimmed node list kept an old currentNodeId; prompt templates with placeholder ids leaked into output.","solutions":["Verify currentNodeId appears exactly (string equality, case-sensitive) among the node ids in the JSON.","Retry the organize call asking the model to set currentNodeId to one of the listed node ids, or to omit it for null.","If no node is meaningfully 'current', drop the field so it defaults to null.","When post-processing, clamp currentNodeId to an existing id before calling parseOrganization."],"exampleFix":"// before\n{\"nodes\":[{\"id\":\"n1\",...}],\"currentNodeId\":\"n2\"}\n// after\n{\"nodes\":[{\"id\":\"n1\",...}],\"currentNodeId\":\"n1\"}","handlingStrategy":"validation","validationCode":"function currentNodeExists(org){ const cn=org?.currentNodeId; return cn==null || (org?.nodes||[]).some(n=>n?.id===cn); }","typeGuard":"function isValidCurrentNode(cn, nodes){ return cn === null || cn === undefined || (Array.isArray(nodes) && nodes.some(n => n?.id === cn)); }","tryCatchPattern":"try { const org = parseOrganization(text, messages, requestId); } catch (e) { if (e.message === '当前推进节点不存在') { /* clamp currentNodeId to an existing id or null and retry */ } else throw e; }","preventionTips":["Tell the model currentNodeId must be one of the ids it just listed, or omitted entirely.","Treat currentNodeId as optional; omit when no node is in progress.","Clamp stale pointers to null after node-list edits."],"tags":["validation","dangling-reference","llm-output"],"backgroundTag":"entity-not-found","analyzedSha":"b1ed92e5e4a2d74095d4b8db5af43cef7acba9c6","analyzedAt":"2026-09-19T23:35:21.129Z","contentChangedAt":"2026-09-19T23:35:21.129Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}