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

  1. 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.
  2. 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.
  3. Confirm file read permissions on the Codex sessions directory so the backend can read the full rollout file.
  4. 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

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)