Fix: ElizaOS pgvector Dimension Mismatch (1536 vs 768 / 384) Crash
When deploying autonomous AI agent swarms using ElizaOS (formerly ai16z Eliza) paired with a PostgreSQL and pgvector backend, engineers often encounter an immediate fatal crash during agent initialization or memory recall:
error: different vector dimensions 768 and 1536
at Parser.parseErrorMessage (/node_modules/pg-protocol/dist/parser.js:287:98)
at PostgresDatabaseAdapter.searchMemoriesByEmbedding (/packages/adapter-postgres/src/index.ts:412:15)
[ERROR] Agent runtime crashed on boot: Failed to load character memories.
The error occurs immediately after modifying character.json or .env to switch embedding providers—typically transitioning from proprietary cloud models (OpenAI text-embedding-3-small / text-embedding-ada-002 at 1536 dimensions) to self-hosted local models (Ollama nomic-embed-text at 768 dimensions or bge-small-en-v1.5 at 384 dimensions).
If your agent is also crashing on OpenAI structured output parsing, review our diagnostic guide on Resolving ElizaOS Failed to Parse JSON OpenAI Errors.
Architectural Breakdown: Strict pgvector Dimensionality Constraints
In PostgreSQL, the pgvector extension defines vector columns with a mandatory compile-time or schema-level length parameter:
$$\text{embedding} \quad \text{vector}(D)$$
Why pgvector Forbids Dimension Mismatches
- Memory Representation: pgvector stores vectors as contiguous arrays of single-precision floating-point numbers ($4 \times D$ bytes). Index types like HNSW (Hierarchical Navigable Small World) and IVFFlat construct distance graphs based on fixed-length metric calculations (Cosine, Euclidean $L_2$, or Inner Product).
- Mathematical Incompatibility: Calculating the cosine distance: $$\cos(\theta) = \frac{\mathbf{u} \cdot \mathbf{v}}{|\mathbf{u}|_2 |\mathbf{v}|_2}$$ is mathematically undefined when $\mathbf{u} \in \mathbb{R}^{768}$ and $\mathbf{v} \in \mathbb{R}^{1536}$.
- ElizaOS Adapter Schema Hardcoding: Older versions of
@elizaos/adapter-postgrescreate thememoriestable withembedding vector(1536)by default. When an Ollama model emits a 768-element array, the PostgreSQL wire protocol parser halts execution.
Step-by-Step Resolution Protocol
To resolve the dimension mismatch without wiping your entire Postgres database or corrupting existing memories, execute this three-stage migration.
1. Execute Non-Destructive PostgreSQL Column Alteration
Connect to your PostgreSQL database instance (via psql or pgAdmin) and alter the vector column to the target dimensionality of your new model.
Option A: Clean Cutover for Fresh Agents (Drops Old Indices)
If you are developing or can afford to regenerate historical embeddings:
-- Connect to your eliza database
\c eliza_db;
-- 1. Drop existing HNSW or IVFFlat vector index
DROP INDEX IF EXISTS memories_embedding_hnsw_idx;
DROP INDEX IF EXISTS memories_embedding_idx;
-- 2. Alter column to match your new embedding dimension (e.g., 768 for nomic-embed-text)
ALTER TABLE memories
ALTER COLUMN embedding TYPE vector(768);
-- 3. Recreate the high-performance HNSW index for the new dimension
CREATE INDEX memories_embedding_hnsw_idx
ON memories
USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 64);
Option B: Dual-Column Architecture (Preserves Historical Memories)
If you have critical agent conversations embedded at 1536 dimensions that must be preserved:
-- Add a dedicated column for the local model
ALTER TABLE memories ADD COLUMN IF NOT EXISTS embedding_768 vector(768);
-- Create an HNSW index for the secondary column
CREATE INDEX IF NOT EXISTS memories_embedding_768_hnsw_idx
ON memories
USING hnsw (embedding_768 vector_cosine_ops);
2. Configure ElizaOS Character Configuration
Ensure your characters/your-agent.character.json file explicitly declares the embedding model and dimensions so the runtime does not default to OpenAI parameters:
{
"name": "SentinelAgent",
"modelProvider": "ollama",
"settings": {
"voice": {
"model": "en_US-male-medium"
},
"embeddingModel": "nomic-embed-text",
"embeddingDimension": 768
},
"plugins": []
}
3. Implement Runtime Defensive Embedding Adapter
In custom TypeScript scripts or agent extensions, intercept embeddings before dispatch to PostgreSQL to catch length anomalies before they trigger SQL transaction rollbacks:
// src/utils/embeddingGuard.ts
export function validateEmbeddingDimension(embedding: number[], expectedDim: number): number[] {
if (!Array.isArray(embedding)) {
throw new Error('EMBEDDING_ERROR: Output is not a valid numerical array.');
}
if (embedding.length !== expectedDim) {
console.error(
`[EmbeddingGuard] Critical dimension mismatch! Got ${embedding.length}, expected ${expectedDim}.`
);
// Defensive strategy: If smaller, pad with zeros; if larger, slice (temporary fallback)
if (embedding.length < expectedDim) {
const padded = new Array(expectedDim).fill(0);
for (let i = 0; i < embedding.length; i++) padded[i] = embedding[i];
return padded;
} else {
return embedding.slice(0, expectedDim);
}
}
return embedding;
}
Model Dimension Reference Matrix
| Provider | Embedding Model Name | Vector Dimensions | Recommended HNSW Distance |
|---|---|---|---|
| OpenAI | text-embedding-3-small | 1536 (or customizable) | vector_cosine_ops |
| OpenAI | text-embedding-3-large | 3072 | vector_cosine_ops |
| Ollama | nomic-embed-text | 768 | vector_cosine_ops |
| Ollama | mxbai-embed-large | 1024 | vector_cosine_ops |
| HuggingFace | BAAI/bge-small-en-v1.5 | 384 | vector_cosine_ops |
| HuggingFace | BAAI/bge-large-en-v1.5 | 1024 | vector_cosine_ops |
Frequently Asked Questions
Q: Why doesn’t ElizaOS automatically detect the embedding dimension on startup?
In current versions of @elizaos/core, the database schema migration runs once during initial deployment (initDatabase). If the table was initialized under OpenAI’s 1536-dimension schema, subsequent agent launches assume the database column matches whatever model is defined in the character file.
Q: Can I use text-embedding-3-small with 768 dimensions directly?
Yes. OpenAI’s text-embedding-3 models support native dimension reduction via MRL (Matryoshka Representation Learning). You can pass { dimensions: 768 } in your API options, allowing you to match a 768-dimension schema without switching away from OpenAI.
Q: What happens if I query the database with a zero-padded vector?
Zero-padding preserves array length to avoid database errors, but it degrades retrieval accuracy because the geometric cosine angle is distorted. Zero-padding should only be used as a non-crashing fail-safe while a background script backfills genuine embeddings.