BigPizzaV3/CodexPlusPlus · error

sidebar catalog row is missing thread_id

Error message

sidebar catalog row is missing thread_id

What it means

Every row in a sidebar catalog entry must carry a string "thread_id" so the restore can verify the row belongs to the snapshot's thread. A row without the field aborts the restore. This prevents injecting rows for unrelated threads through a snapshot.

Solutions

  1. Add "thread_id": "<same id as snapshot thread_id>" to each row object
  2. Ensure every row's thread_id matches the snapshot's top-level thread_id exactly (see also the mismatch error)
  3. Re-export the snapshot so rows are complete
  4. Drop rows that are missing thread_id instead of restoring partial data

Example fix

// before
{ "title": "My thread", "updated_at": 123 }
// after
{ "thread_id": "3f9c...", "title": "My thread", "updated_at": 123 }
Defensive patterns

Strategy: validation

Validate before calling

const tid = snapshot.thread_id;
for (const e of snapshot.catalog ?? []) {
  for (const row of e.rows ?? []) {
    if (typeof row?.thread_id !== 'string' || row.thread_id !== tid) {
      throw new Error('row thread_id missing or mismatched');
    }
  }
}

Type guard

function rowHasThreadId(row, tid) {
  return typeof row?.thread_id === 'string' && row.thread_id === tid;
}

Try / catch

try {
  restore_sidebar_snapshot(&snapshot, codex_home)?;
} catch (e) {
  if (String(e).includes('row is missing thread_id')) {
    dropOrRepairRowsWithoutThreadId(snapshot);
  }
}

Prevention

When it happens

Trigger: A row object inside entry["rows"] that has no "thread_id" key or whose value is not a string, passed to the sidebar snapshot restore function.

Common situations: Rows copied from another snapshot or table without their thread_id; hand-edited rows; partial row objects assembled manually; exporter version with differently shaped rows.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at crates/codex-plus-data/src/provider_sync.rs:2728

            }
            let path = entry
                .get("db_path")
                .and_then(Value::as_str)
                .map(PathBuf::from)
                .ok_or_else(|| anyhow::anyhow!("sidebar catalog entry is missing db_path"))?;
            let canonical = fs::canonicalize(&path)?;
            if !allowed_paths.contains(&canonical) {
                anyhow::bail!("sidebar catalog database is not an allowed Codex database");
            }
            let rows = entry
                .get("rows")
                .and_then(Value::as_array)
                .ok_or_else(|| anyhow::anyhow!("sidebar catalog entry rows must be an array"))?;
            for row in rows {
                let row_id = row
                    .get("thread_id")
                    .and_then(Value::as_str)
                    .ok_or_else(|| anyhow::anyhow!("sidebar catalog row is missing thread_id"))?;
                if row_id != thread_id {
                    anyhow::bail!("sidebar catalog row thread_id does not match snapshot");
                }
            }
        }
    }
    Ok(())
}

const SIDEBAR_CATALOG_TABLES: [&str; 3] = [
    "local_thread_catalog",
    "thread_timeline_ledger",
    "local_thread_catalog_scan_entries",
];

fn snapshot_thread_from_global_state(
    codex_home: &Path,
    thread_id: &str,

View on GitHub (pinned to b1ed92e5e4)