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
- Inspect the actual schema: sqlite3 source.db 'PRAGMA table_info(memories);' and find which column holds the memory text
- Rename it to a recognized name: ALTER TABLE memories RENAME COLUMN <old> TO content; (SQLite 3.25+)
- If the schema is from an unsupported OpenClaw version, export rows to JSON/text and import into ZeroClaw memories manually
- 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
- Pre-flight the source DB schema before starting a migration
- Pin supported OpenClaw versions and validate their schema in a test matrix
- Back up the source DB before any ALTER TABLE workaround
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
- OpenClaw workspace not found at {}. Pass --source <path> if
- Source workspace matches current ZeroClaw workspace; refusin
- purge_agent not supported by this memory backend
- knowledge graph node limit reached ({}/{})
- Unable to allocate non-conflicting key for '{base}'
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/49983f7e8869b2fa.
Report an issue: GitHub.