zeroclaw-labs/zeroclaw · error · anyhow::Error

OpenClaw memories table found but no content-like column was

Error message

OpenClaw memories table found but no content-like column was detected

What it means

When the migration source contains a SQLite database with a memories table, read_openclaw_sqlite_entries inspects its columns via PRAGMA table_info(memories). It picks a key expression (key/id/name, else rowid) and then requires one content-bearing column among content, value, text, or memory. If none of those exist the schema is unrecognized and it bails rather than importing garbage.

Source

Thrown at crates/zeroclaw-runtime/src/migration.rs:193

    let table_exists: Option<String> = conn
        .query_row(
            "SELECT name FROM sqlite_master WHERE type='table' AND name='memories' LIMIT 1",
            [],
            |row| row.get(0),
        )
        .optional()?;

    if table_exists.is_none() {
        return Ok(Vec::new());
    }

    let columns = table_columns(&conn, "memories")?;
    let key_expr = pick_column_expr(&columns, &["key", "id", "name"], "CAST(rowid AS TEXT)");
    let Some(content_expr) =
        pick_optional_column_expr(&columns, &["content", "value", "text", "memory"])
    else {
        bail!("OpenClaw memories table found but no content-like column was detected");
    };
    let category_expr = pick_column_expr(&columns, &["category", "kind", "type"], "'core'");

    let sql = format!(
        "SELECT {key_expr} AS key, {content_expr} AS content, {category_expr} AS category FROM memories"
    );

    let mut stmt = conn.prepare(&sql)?;
    let mut rows = stmt.query([])?;

    let mut entries = Vec::new();
    let mut idx = 0_usize;

    while let Some(row) = rows.next()? {
        let key: String = row
            .get(0)
            .unwrap_or_else(|_| format!("openclaw_sqlite_{idx}"));
        let content: String = row.get(1).unwrap_or_default();

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Inspect the actual schema: sqlite3 source.db 'PRAGMA table_info(memories);' and find which column holds the memory text
  2. Rename it to a recognized name: ALTER TABLE memories RENAME COLUMN <old> TO content; (SQLite 3.25+)
  3. If the schema is from an unsupported OpenClaw version, export rows to JSON/text and import into ZeroClaw memories manually
  4. Verify you pointed --source at a genuine OpenClaw workspace

Example fix

-- before: memories(body TEXT, key TEXT)
ALTER TABLE memories RENAME COLUMN body TO content;
-- after: memories(content TEXT, key TEXT) — migration proceeds
Defensive patterns

Strategy: validation

Validate before calling

let conn = Connection::open(&db_path)?;
let cols: Vec<String> = table_columns(&conn, "memories")?;
let has_content = ["content", "value", "text", "memory"].iter().any(|c| cols.iter().any(|x| x == c));
if !has_content {
    // tell the user which columns exist and suggest ALTER TABLE ... RENAME COLUMN
}

Try / catch

Err(e) if e.to_string().contains("no content-like column") => {
    // inspect PRAGMA table_info(memories) with the user; unsupported schema — do not retry unchanged
}

Prevention

When it happens

Trigger: Migrating an OpenClaw database from a fork or a version whose memories table uses a different content column name; a database where the content column was renamed or dropped; a memories table created by unrelated software inside the source workspace; a truncated/partially-migrated DB.

Common situations: Schema drift between OpenClaw versions; users pointing --source at a directory that merely looks like an OpenClaw workspace; databases restored from backups with later manual ALTERs.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/49983f7e8869b2fa. Report an issue: GitHub.