BigPizzaV3/CodexPlusPlus · error
无法读取完整 Codex 会话文件
Error message
无法读取完整 Codex 会话文件
What it means
This error is thrown by the CodexPlusPlus session-share flow in renderer-inject.js when exporting a Codex session for sharing. The code calls POST /session/export and expects a response with status "ok", kind "codex-rollout", and a string content field (the raw rollout file). If any of those checks fail — or the endpoint itself reports an error message — the flow aborts with "无法读取完整 Codex 会话文件" ("cannot read the complete Codex session file"), because the encrypted share payload cannot be built without the full session document.
Solutions
- Verify the session_id exists and the rollout file on disk is complete (not truncated); re-open or re-select the session and retry the share.
- Check the /session/export backend response (status/kind/content) — if status is not "ok", use its message field to identify the underlying server-side cause.
- Confirm file read permissions on the Codex sessions directory so the backend can read the full rollout file.
- Upgrade CodexPlusPlus client and backend together so the export response shape (kind: "codex-rollout", string content) matches.
Example fix
// before: assume export always succeeds
const nativeSession = await postJson("/session/export", { session_id });
shareDocument = { ...nativeSession, title: session.title };
// after: guard the response shape before using it
const nativeSession = await postJson("/session/export", { session_id });
if (nativeSession?.status !== "ok" || nativeSession.kind !== "codex-rollout" || typeof nativeSession.content !== "string") {
throw new Error(nativeSession?.message || "无法读取完整 Codex 会话文件");
} Defensive patterns
Strategy: type-guard
Validate before calling
const res = await postJson("/session/export", { session_id });
if (res?.status !== "ok" || res.kind !== "codex-rollout" || typeof res.content !== "string") {
throw new Error(res?.message || "会话导出不可用");
} Type guard
function isCodexRolloutExport(v) {
return v != null && typeof v === "object" && v.status === "ok" && v.kind === "codex-rollout" && typeof v.content === "string";
} Try / catch
try {
shareDocument = await exportSession(ref.session_id, session.title);
} catch (e) {
console.error("会话导出失败,已取消分享:", e);
showToast("无法读取完整 Codex 会话文件,请确认会话仍存在后重试");
return;
} Prevention
- Always validate the export response shape before consuming content.
- Keep client and backend versions in sync so the response contract (kind/content) stays stable.
- Check session/rollout file existence server-side and return a precise message instead of a truncated export.
When it happens
Trigger: Calling the share/export action when: the /session/export endpoint returns status !== "ok"; the response kind is not "codex-rollout" (e.g. truncated or partial export); content is missing or not a string; or the backend returns its own error message which is used as the thrown message.
Common situations: The Codex rollout/session file was rotated, deleted, or truncated on disk before export; session_id points to an expired or non-existent session; the backend proxy cannot read the rollout file due to permissions; a version mismatch where the export endpoint changed its response shape (kind/content fields).
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/3af745aaff7264a9.
Report an issue: GitHub.
Appendix: source
Thrown at assets/inject/renderer-inject.js:7585
if (!markdown || !session) {
showToast("当前会话还没有可分享的消息", null);
return;
}
const shareWindow = window.open("about:blank", "_blank");
const button = document.querySelector(`.${sessionShareButtonClass}`);
if (button) {
button.disabled = true;
button.setAttribute("aria-busy", "true");
button.textContent = "正在创建…";
}
try {
let shareDocument = session;
const nativeSession = await postJson("/session/export", {
session_id: ref.session_id,
title: session.title,
});
if (nativeSession?.status !== "ok" || nativeSession.kind !== "codex-rollout" || typeof nativeSession.content !== "string") {
throw new Error(nativeSession?.message || "无法读取完整 Codex 会话文件");
}
shareDocument = { ...nativeSession, title: session.title };
const encrypted = await encryptSessionShare(JSON.stringify(shareDocument));
const payload = { ttl: 604800, encrypted: encrypted.encrypted };
let result;
let baseUrl = codexPlusShareBaseUrl;
try {
result = await postJson("/share/create", payload);
if (result?.id) {
baseUrl = codexPlusShareBaseUrl;
} else if (result?.status !== "failed") {
throw new Error(result?.message || "创建分享失败");
}
} catch (_) {
result = null;
}
if (!result?.id) {
let response;View on GitHub (pinned to b1ed92e5e4)