How to fix SQLITE_TOOBIG: String or BLOB exceeds size limit in SQLite

SQLiteINTERMEDIATEMEDIUMUpdated Dec 22, 2025ยท 326 views

This error occurs when attempting to store a string or BLOB that exceeds SQLite's maximum allowed size, typically 1 billion bytes by default. It can also trigger when an SQL statement itself is too long.

Quick fix

Fixes SQLITE_TOOBIG

// Node.js example
const fs = require('fs');
const fileSize = fs.statSync('largefile.bin').size;
console.log(`File size: ${fileSize} bytes (${(fileSize / 1024 / 1024).toFixed(2)} MB)`);

if (fileSize > 500_000_000) { // 500 MB threshold
  console.warn('File may exceed SQLite recommended limits');
}
  1. Check your data size before insertion
  2. Store large files outside the database
  3. Implement data chunking for large BLOBs
  4. Increase SQLITE_MAX_LENGTH at runtime (if applicable)
sqlite โ€” error
// Node.js example
const fs = require('fs');
const fileSize = fs.statSync('largefile.bin').size;
console.log(`File size: ${fileSize} bytes (${(fileSize / 1024 / 1024).toFixed(2)} MB)`);
if (fileSize > 500_000_000) { // 500 MB threshold
console.warn('File may exceed SQLite recommended limits');
}
SQLITE_TOOBIG: String or BLOB exceeds size limit

What this error means

The SQLITE_TOOBIG error (error code 18) indicates that SQLite has encountered a string, BLOB (Binary Large Object), or SQL statement that exceeds the compiled maximum length limit. By default, SQLite's SQLITE_MAX_LENGTH is set to 1 billion bytes (1,000,000,000), though the absolute hard limit is 2^31-1 bytes (approximately 2.14 GB). This error most commonly occurs when trying to INSERT or UPDATE a column with data that exceeds the size limit, but it can also happen when the SQL statement text itself is too long. SQLite version 3.36 introduced a regression where the default maximum SQL statement length changed from 1 billion bytes to approximately 1 GB, which caught some applications off guard. The limit applies not just to individual column values, but also to complete rows during INSERT and SELECT operations, since SQLite internally encodes entire rows as single BLOBs during processing. This means the SQLITE_MAX_LENGTH parameter effectively determines both the maximum individual field size and maximum row size.

Typical symptoms

  • INSERT or UPDATE operations fail with "string or blob too big" error
  • Application crashes when attempting to store large binary files in database
  • Error occurs when executing very long SQL statements or queries
  • Works fine with small data but fails when data size increases beyond threshold
  • Error message may specify "SQLITE_TOOBIG" or error code 18
  • In some environments (like Cloudflare Durable Objects), limit may be much lower (2MB) than default

Common causes

  1. Attempting to store a string or BLOB larger than SQLITE_MAX_LENGTH (default 1 billion bytes)
  2. SQL statement text exceeds the maximum allowed length (1 million characters default)
  3. Trying to store files or binary data larger than 1-2 GB in a single column
  4. Environment-specific limits (e.g., Cloudflare Workers has 2MB limit for Durable Objects)
  5. Complete row size exceeds limit when encoded as a single BLOB during processing
  6. Compiling SQLite with a reduced SQLITE_MAX_LENGTH for security reasons
  7. Using SQLite 3.36+ where default max SQL length was reduced from 1B to ~1GB bytes

How to fix "SQLITE_TOOBIG: String or BLOB exceeds size limit"

1Check your data size before insertion

Before attempting to insert large data, verify its size to understand if you're approaching SQLite's limits:

javascript
// Node.js example
const fs = require('fs');
const fileSize = fs.statSync('largefile.bin').size;
console.log(`File size: ${fileSize} bytes (${(fileSize / 1024 / 1024).toFixed(2)} MB)`);

if (fileSize > 500_000_000) { // 500 MB threshold
  console.warn('File may exceed SQLite recommended limits');
}
python
# Python example
import os

file_size = os.path.getsize('largefile.bin')
print(f"File size: {file_size} bytes ({file_size / 1024 / 1024:.2f} MB)")

if file_size > 500_000_000:
    print("Warning: File may exceed SQLite recommended limits")

SQLite's default maximum is 1 billion bytes, but practical limits are often lower. If your data exceeds 100-500 MB, consider alternative storage strategies.

2Store large files outside the database

The recommended approach for large binary data is to store files in the filesystem and keep only references in SQLite:

javascript
// Node.js example with file storage
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

async function storeFile(fileBuffer, db) {
  // Generate unique filename
  const hash = crypto.createHash('sha256').update(fileBuffer).digest('hex');
  const filename = `${hash.substring(0, 16)}.bin`;
  const filePath = path.join('./uploads', filename);

  // Write to filesystem
  await fs.promises.writeFile(filePath, fileBuffer);

  // Store reference in database
  await db.run(
    'INSERT INTO files (filename, path, size, created_at) VALUES (?, ?, ?, ?)',
    [filename, filePath, fileBuffer.length, new Date().toISOString()]
  );

  return filename;
}
python
# Python example with file storage
import sqlite3
import hashlib
from pathlib import Path
from datetime import datetime

def store_file(file_data: bytes, db_conn):
    # Generate unique filename
    hash_obj = hashlib.sha256(file_data)
    filename = f"{hash_obj.hexdigest()[:16]}.bin"
    file_path = Path("./uploads") / filename

    # Write to filesystem
    file_path.parent.mkdir(exist_ok=True)
    file_path.write_bytes(file_data)

    # Store reference in database
    db_conn.execute(
        "INSERT INTO files (filename, path, size, created_at) VALUES (?, ?, ?, ?)",
        (filename, str(file_path), len(file_data), datetime.now().isoformat())
    )
    db_conn.commit()

    return filename

This is the same strategy used by iTunes, Plex, and other applications that manage large media files.

3Implement data chunking for large BLOBs

If you must store large data in SQLite, split it into smaller chunks across multiple rows:

javascript
// Node.js chunking example
const CHUNK_SIZE = 1024 * 1024; // 1 MB chunks

async function insertLargeBlob(fileBuffer, fileId, db) {
  const totalChunks = Math.ceil(fileBuffer.length / CHUNK_SIZE);

  for (let i = 0; i < totalChunks; i++) {
    const start = i * CHUNK_SIZE;
    const end = Math.min(start + CHUNK_SIZE, fileBuffer.length);
    const chunk = fileBuffer.slice(start, end);

    await db.run(
      'INSERT INTO blob_chunks (file_id, chunk_index, chunk_data, total_chunks) VALUES (?, ?, ?, ?)',
      [fileId, i, chunk, totalChunks]
    );
  }
}

async function retrieveLargeBlob(fileId, db) {
  const chunks = await db.all(
    'SELECT chunk_data FROM blob_chunks WHERE file_id = ? ORDER BY chunk_index',
    [fileId]
  );

  return Buffer.concat(chunks.map(row => row.chunk_data));
}
python
# Python chunking example
CHUNK_SIZE = 1024 * 1024  # 1 MB chunks

def insert_large_blob(file_data: bytes, file_id: str, db_conn):
    total_chunks = (len(file_data) + CHUNK_SIZE - 1) // CHUNK_SIZE

    for i in range(total_chunks):
        start = i * CHUNK_SIZE
        end = min(start + CHUNK_SIZE, len(file_data))
        chunk = file_data[start:end]

        db_conn.execute(
            "INSERT INTO blob_chunks (file_id, chunk_index, chunk_data, total_chunks) VALUES (?, ?, ?, ?)",
            (file_id, i, chunk, total_chunks)
        )

    db_conn.commit()

def retrieve_large_blob(file_id: str, db_conn):
    cursor = db_conn.execute(
        "SELECT chunk_data FROM blob_chunks WHERE file_id = ? ORDER BY chunk_index",
        (file_id,)
    )

    chunks = [row[0] for row in cursor.fetchall()]
    return b''.join(chunks)

Create the chunks table:

sql
CREATE TABLE blob_chunks (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  file_id TEXT NOT NULL,
  chunk_index INTEGER NOT NULL,
  chunk_data BLOB NOT NULL,
  total_chunks INTEGER NOT NULL,
  UNIQUE(file_id, chunk_index)
);

CREATE INDEX idx_blob_chunks_file ON blob_chunks(file_id);
4Increase SQLITE_MAX_LENGTH at runtime (if applicable)

For some SQLite implementations, you can adjust the maximum blob size at runtime using PRAGMA:

sql
-- Check current limit (returns value in bytes)
PRAGMA max_page_count;
PRAGMA page_size;

-- Attempt to set maximum blob size (not all implementations support this)
PRAGMA max_blob_size = 2000000000; -- ~2 GB
javascript
// Node.js with better-sqlite3
const Database = require('better-sqlite3');
const db = new Database('mydb.sqlite');

// Note: max_blob_size PRAGMA is not universally supported
try {
  db.pragma('max_blob_size = 2000000000');
  console.log('Blob size limit increased');
} catch (error) {
  console.error('Cannot adjust blob size at runtime:', error.message);
}

Important: This PRAGMA is not supported in all SQLite builds. Most applications should rely on compile-time limits or use chunking/external storage instead. Additionally, increasing limits beyond default values can introduce security risks and performance issues.

5Recompile SQLite with higher SQLITE_MAX_LENGTH (advanced)

If you control the SQLite compilation and absolutely need larger limits, you can recompile with a custom SQLITE_MAX_LENGTH:

bash
# Download SQLite source
wget https://www.sqlite.org/2025/sqlite-amalgamation-3XXXXXX.zip
unzip sqlite-amalgamation-3XXXXXX.zip
cd sqlite-amalgamation-3XXXXXX

# Compile with custom max length (2 GB - near absolute limit)
gcc -DSQLITE_MAX_LENGTH=2147483647 \
    -DSQLITE_MAX_SQL_LENGTH=2147483647 \
    -O2 -o sqlite3 shell.c sqlite3.c -lpthread -ldl

# Install custom build
sudo cp sqlite3 /usr/local/bin/sqlite3-custom

For Node.js applications using better-sqlite3, you'd need to compile the native module:

bash
# Clone and modify better-sqlite3
git clone https://github.com/WiseLibs/better-sqlite3.git
cd better-sqlite3

# Edit deps/common.gypi to add compile flags
# Add to 'defines': ['SQLITE_MAX_LENGTH=2147483647']

npm install
npm run build-release

Warning:
- Increasing limits can introduce security vulnerabilities and memory issues
- SQLite performance degrades significantly with multi-gigabyte rows
- The absolute hard limit is 2^31-1 bytes (2.14 GB) regardless of compilation flags
- Consider whether your use case truly requires such large values in a database

Advanced notes

### Platform-Specific Limits

Different SQLite environments impose varying limits:

- Standard SQLite: 1 billion bytes default, up to ~2.14 GB hard limit
- Cloudflare Durable Objects: 2 MB limit per BLOB
- Mobile platforms (iOS/Android): Often use reduced limits for memory constraints
- SQLite 3.36+: Default max SQL statement length reduced from 1B to ~1GB bytes

### Security Considerations

In security-sensitive applications, lower limits are actually preferable:

> "In fact, you might do well to lower the maximum string and blob length to something more in the range of a few million if that is possible." - SQLite Documentation

Reasons to keep limits low:
- Prevents denial-of-service attacks via oversized data
- Reduces memory exhaustion risks
- Forces proper architectural decisions (external file storage)
- Improves database backup/replication performance

### Performance Impact

Large BLOBs significantly impact SQLite performance:

- Memory usage: Entire rows are loaded into memory during processing
- Page fragmentation: Large BLOBs span many pages, increasing I/O
- Backup time: Larger databases take longer to backup
- Locking: Long operations on large BLOBs can block other transactions

### Incremental BLOB I/O

SQLite's C API provides incremental BLOB I/O functions for reading/writing large BLOBs in chunks without loading the entire value into memory:

- sqlite3_blob_open()
- sqlite3_blob_read()
- sqlite3_blob_write()

However, most language bindings (Node.js, Python, etc.) don't expose these APIs. If you need this functionality, consider:

1. Using the C API directly via FFI
2. Using SQLite's substr() function to read chunks: SELECT substr(blob_column, offset, length)
3. Implementing application-level chunking (recommended)

### Alternative Databases for Large Objects

If you frequently need to store multi-gigabyte objects, consider alternatives:

- Object storage: AWS S3, Google Cloud Storage, Azure Blob Storage
- Document databases: MongoDB (16 MB limit per document, but GridFS for larger)
- Key-value stores: Redis (512 MB limit), Memcached
- Filesystem + metadata DB: Hybrid approach (recommended for most use cases)

SQLite excels at structured, relational data up to several hundred megabytes. For larger objects, external storage with SQLite metadata provides the best balance of performance, reliability, and maintainability.

Frequently asked questions

What does "SQLITE_TOOBIG" mean?
The SQLITE_TOOBIG error (error code 18) indicates that SQLite has encountered a string, BLOB (Binary Large Object), or SQL statement that exceeds the compiled maximum length limit. 14 GB). This error most commonly occurs when trying to INSERT or UPDATE a column with data that exceeds the size limit, but it can also happen when the SQL statement text itself is too long.
How do I fix "SQLITE_TOOBIG"?
This error occurs when attempting to store a string or BLOB that exceeds SQLite's maximum allowed size, typically 1 billion bytes by default. It can also trigger when an SQL statement itself is too long.
What causes "SQLITE_TOOBIG"?
Attempting to store a string or BLOB larger than SQLITE_MAX_LENGTH (default 1 billion bytes) SQL statement text exceeds the maximum allowed length (1 million characters default) Trying to store files or binary data larger than 1-2 GB in a single column
Is the "SQLITE_TOOBIG" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading