How to fix SQLITE_NOTFOUND: Unknown opcode in sqlite3_file_control() in SQLite
SQLITE_NOTFOUND occurs when code calls sqlite3_file_control() with an opcode that the underlying VFS (Virtual File System) implementation does not recognize or support. This typically happens with custom VFS implementations, version mismatches, or calling opcodes meant for internal use only.
Quick fix
Fixes SQLITE_NOTFOUND
int opcode = SQLITE_FCNTL_SIZE_HINT; // or whichever opcode you are using
int result = sqlite3_file_control(db, "main", opcode, &arg);
if (result == SQLITE_NOTFOUND) {
fprintf(stderr, "Opcode %d not supported by VFS\n", opcode);
}- Check the opcode value being passed to sqlite3_file_control()
- Verify your SQLite version supports the opcode
- Avoid calling internal-only opcodes from application code
- Check if you are using a custom or third-party VFS implementation
int opcode = SQLITE_FCNTL_SIZE_HINT; // or whichever opcode you are usingint result = sqlite3_file_control(db, "main", opcode, &arg);if (result == SQLITE_NOTFOUND) {fprintf(stderr, "Opcode %d not supported by VFS\n", opcode);}SQLITE_NOTFOUND: Unknown opcode in sqlite3_file_control()
What this error means
The sqlite3_file_control() function is a low-level interface that allows direct communication with SQLite's Virtual File System (VFS) layer. It takes an opcode parameter that tells the VFS what operation to perform. When you pass an opcode (an integer code) that the VFS doesn't understand, it returns SQLITE_NOTFOUND (error code 12). Each VFS implementation only recognizes certain opcodes. SQLite core reserves opcodes less than 100 for its own use. Custom applications can define opcodes greater than 100. If a VFS encounters an opcode it doesn't implement, it must return SQLITE_NOTFOUND. This is the expected behavior for unrecognized or unsupported file control operations.
Typical symptoms
- Application crashes or exits with "SQLITE_NOTFOUND" error when calling sqlite3_file_control()
- Database operations fail after attempting advanced file control operations
- Third-party SQLite extensions or custom VFS implementations fail to initialize
- Error message specifically mentions "Unknown opcode" in sqlite3_file_control()
- Code works with standard SQLite VFS but fails with custom or alternative VFS implementations
Common causes
- Calling sqlite3_file_control() with an opcode the current VFS does not support
- Using a custom or legacy VFS implementation that does not implement the required opcode
- SQLite version mismatch—newer opcodes called on older SQLite builds that do not support them
- Directly calling opcodes documented as internal-only (like SQLITE_FCNTL_SYNC or SQLITE_FCNTL_COMMIT_PHASETWO)
- Using third-party VFS extensions (RBU, ZipVFS) expecting opcodes specific to those extensions
- Incorrect opcode value passed due to typos or outdated code using removed opcodes
How to fix "SQLITE_NOTFOUND: Unknown opcode in sqlite3_file_control()"
First, identify which opcode your code is using. Add logging to capture the exact opcode value:
int opcode = SQLITE_FCNTL_SIZE_HINT; // or whichever opcode you are using
int result = sqlite3_file_control(db, "main", opcode, &arg);
if (result == SQLITE_NOTFOUND) {
fprintf(stderr, "Opcode %d not supported by VFS\n", opcode);
}Cross-reference the opcode number against the official SQLite documentation to ensure it is valid and supported in your SQLite version.
Different SQLite versions introduce new opcodes over time. Check your SQLite version and the opcode documentation to confirm the opcode was available at that version.
const char *version = sqlite3_libversion();
fprintf(stderr, "SQLite version: %s\n", version);Upgrade SQLite if you are using a version that does not include the required opcode. Visit https://sqlite.org/download.html to download the latest version.
Some opcodes like SQLITE_FCNTL_SYNC and SQLITE_FCNTL_COMMIT_PHASETWO are generated internally by SQLite and should never be called directly from application code. Do not call sqlite3_file_control() with these opcodes:
- SQLITE_FCNTL_SYNC (internal)
- SQLITE_FCNTL_COMMIT_PHASETWO (internal)
- SQLITE_FCNTL_LOCKSTATE (debug only, requires SQLITE_DEBUG)
If your code is calling these, remove those calls.
If you are using a custom VFS (for example, RBU, ZipVFS, or a custom in-memory VFS), verify that it implements all opcodes you are trying to use.
For example, the RBU (Resumable Bulk Update) extension only implements SQLITE_FCNTL_RBU. All other standard opcodes may not be available. Check the documentation for your VFS:
- Official VFS list: https://sqlite.org/c3ref/c_fcntl_begin_atomic_write.html
- If using RBU: https://sqlite.org/rbu.html
- If using ZipVFS: consult ZipVFS documentation
Either upgrade your VFS to support the opcode, or switch to a VFS that does.
Some opcodes may be unsupported by your VFS because they are optional or not applicable. For common file control needs:
- Chunk size: Use SQLITE_FCNTL_CHUNK_SIZE (opcode 6) to optimize disk allocation.
- WAL persistence: Use SQLITE_FCNTL_PERSIST_WAL (opcode 10) only if your VFS supports it.
- File pointer access: Use SQLITE_FCNTL_FILE_POINTER (opcode 5) or SQLITE_FCNTL_JOURNAL_POINTER (opcode 12).
If an opcode is not supported, the VFS will correctly return SQLITE_NOTFOUND, and your application should handle this gracefully by either:
- Using a default behavior instead
- Trying a different opcode
- Logging a warning and continuing
int result = sqlite3_file_control(db, "main", opcode, &arg);
if (result == SQLITE_NOTFOUND) {
// Handle gracefully: opcode not supported
// Use alternative approach or log warning
fprintf(stderr, "Warning: opcode not supported\n");
}If you are using a custom VFS, temporarily switch to the default VFS to see if the error persists. This helps isolate whether the issue is with the VFS implementation or your opcode usage.
// Use default VFS
sqlite3_open_v2(filename, &db, flags, NULL);If the error goes away with the default VFS, the issue is with your custom VFS implementation. If the error persists, the opcode itself is unsupported or invalid.
Advanced notes
SQLite's VFS system is extensible, but not all VFS implementations support all opcodes. The design is intentional: unsupported opcodes should return SQLITE_NOTFOUND rather than fail silently or corrupt data.
Custom VFS Development: If you are writing a custom VFS, implement xFileControl to handle opcodes your VFS supports and return SQLITE_NOTFOUND for others. Opcodes less than 100 are reserved by SQLite core—use opcodes above 100 for custom extensions.
Version Compatibility: New opcodes are sometimes added between SQLite versions. For example, SQLITE_FCNTL_BEGIN_ATOMIC_WRITE was added in SQLite 3.11.0 (2016). If upgrading SQLite, rebuild your application to ensure you're using the correct header files and libraries.
ZipVFS and RBU: These are specialized VFS implementations. ZipVFS only implements SQLITE_FCNTL_ZIPVFS. RBU only implements SQLITE_FCNTL_RBU. Attempting to call other opcodes on these VFS implementations will return SQLITE_NOTFOUND. For the full set of opcodes, use the default VFS.
Frequently asked questions
- What does "SQLITE_NOTFOUND" mean?
- The sqlite3_file_control() function is a low-level interface that allows direct communication with SQLite's Virtual File System (VFS) layer. It takes an opcode parameter that tells the VFS what operation to perform. When you pass an opcode (an integer code) that the VFS doesn't understand, it returns SQLITE_NOTFOUND (error code 12).
- How do I fix "SQLITE_NOTFOUND"?
- SQLITE_NOTFOUND occurs when code calls sqlite3_file_control() with an opcode that the underlying VFS (Virtual File System) implementation does not recognize or support. This typically happens with custom VFS implementations, version mismatches, or calling opcodes meant for internal use only.
- What causes "SQLITE_NOTFOUND"?
- Calling sqlite3_file_control() with an opcode the current VFS does not support Using a custom or legacy VFS implementation that does not implement the required opcode SQLite version mismatch—newer opcodes called on older SQLite builds that do not support them
- Is the "SQLITE_NOTFOUND" error serious?
- Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.
Official resources & further reading
- 📚SQLite Official Documentation
- 📖SQLite - Low-Level Control Of Database Files(Official Docs)
- 📖SQLite - Standard File Control Opcodes(Official Docs)
- 📖SQLite - Result Codes (SQLITE_NOTFOUND)(Official Docs)