Menu

Error Umum SQLite: Database Locked, Readonly, Malformed, dan Lainnya

Error SQLite yang benar-benar akan kamu temui di production, seperti database is locked, readonly database, disk image malformed, dan kegagalan constraint, beserta cara memperbaikinya.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Error Hanyalah Cara SQLite Memberi Tahu Sesuatu

Pesan error SQLite pendek dan kadang membingungkan, tapi semuanya mengarah ke sekumpulan kecil masalah dasar. Sebagian besar yang akan kamu temui di production masuk ke lima kelompok: locking, izin akses, kerusakan file, ketidakcocokan skema, dan pelanggaran constraint. Halaman ini membahas masing-masing: apa pemicunya, apa arti sebenarnya, dan cara memperbaikinya.

Pesan error datang berpasangan dengan kode angka (kode extended bahkan lebih spesifik). Kamu akan melihat kedua bentuk itu di log:

Error: database is locked          -- code 5 (SQLITE_BUSY)
Error: unable to open database     -- code 14 (SQLITE_CANTOPEN)
Error: attempt to write a readonly -- code 8 (SQLITE_READONLY)
Error: database disk image is      -- code 11 (SQLITE_CORRUPT)

Mengetahui kodenya membantu saat mencari solusi: SQLITE_BUSY memberi hasil pencarian yang jauh lebih baik daripada pesan berbahasa Inggris biasa.

database is locked (SQLITE_BUSY)

Ini error SQLite paling umum di aplikasi mana pun yang menulis dari lebih dari satu tempat. SQLite menjalankan penulisan secara berurutan: hanya satu koneksi yang bisa memegang write lock dalam satu waktu. Kalau penulis kedua tidak mendapatkan lock dalam batas busy timeout, kamu mendapat error ini.

Ada tiga perbaikan, diurutkan dari yang paling berdampak:

Mode WAL saja sudah menyelesaikan masalah locking untuk sebagian besar beban kerja. Busy timeout adalah jaring pengamanmu untuk perebutan penulisan yang sebenarnya. Selain pengaturan, periksa juga kodemu: transaksi yang dibiarkan terbuka saat program melakukan I/O jaringan akan memegang lock selama itu. Buat transaksi tetap singkat, dan lakukan COMMIT (atau ROLLBACK) begitu pekerjaannya selesai.

unable to open database file (SQLITE_CANTOPEN)

SQLite mencoba membuka file dan sistem operasi menolaknya. Path file atau direktorinya adalah penyebabnya di 95% kasus:

-- Things to check:
-- 1. Does the path exist?            ls -l /path/to/db.sqlite
-- 2. Does the parent directory exist? SQLite creates the file
--    but not the directory above it.
-- 3. Does the user running your process have read+write
--    permission on the directory (not just the file)?
-- 4. Is the volume mounted, not full, and not read-only?

Satu kasus yang halus: SQLite perlu membuat file pendamping (-journal, -wal, -shm) di sebelah database. Kalau file-nya bisa ditulisi tapi direktorinya tidak, pembukaan berhasil tapi penulisan gagal. Selalu berikan izin tulis di tingkat direktori.

attempt to write a readonly database (SQLITE_READONLY)

Ini kerabat dekat error sebelumnya. File berhasil dibuka, tapi penulisan gagal. Penyebabnya, diurutkan dari yang paling sering:

  • User sistem operasi tidak punya izin tulis pada file atau direktorinya.
  • Koneksi dibuka dengan flag read-only (SQLITE_OPEN_READONLY, atau mode=ro di URI).
  • Volume di-mount sebagai read-only (sering terjadi pada bind mount Docker dan beberapa filesystem cloud).
  • Database berada di filesystem jaringan yang tidak mendukung mekanisme locking yang dibutuhkan SQLite.

Perbaiki izinnya atau mount ulang volumenya. Kalau kamu memakai Docker, pastikan bind mount-nya bukan :ro dan user container memiliki direktori tersebut.

database disk image is malformed (SQLITE_CORRUPT)

Byte di file tidak lagi cocok dengan format SQLite. Penyebab sebenarnya biasanya dari lingkungan: proses yang dimatikan di tengah penulisan pada filesystem tanpa fsync yang benar, menyalin database saat ada penulis yang aktif, kerusakan hardware, atau menyinkronkan file lewat Dropbox/iCloud.

Pertama, pastikan kerusakannya:

Kalau integrity_check mengembalikan ok, database-mu baik-baik saja dan error-nya berasal dari tempat lain (sering dari koneksi yang sudah usang). Kalau yang dikembalikan adalah daftar masalah, kamu perlu melakukan pemulihan.

Jalur pemulihan paling bersih memakai perintah .recover di CLI, yang mengambil data apa pun yang masih bisa diselamatkan ke database baru:

sqlite3 corrupt.db ".recover" | sqlite3 recovered.db
sqlite3 recovered.db "PRAGMA integrity_check;"

Kalau kamu punya backup terbaru, restore dari situ saja: lebih cepat dan menghindari ketidakpastian "sebagian besar datanya berhasil kembali." Lihat halaman backup dan restore untuk cara yang benar menyalin database yang sedang dipakai (petunjuk: bukan cp).

no such table dan no such column

Artinya persis seperti yang tertulis, tapi penyebabnya biasanya satu dari dua hal: kamu terhubung ke database yang berbeda dari yang kamu kira, atau ada migrasi yang tidak berjalan.

Periksa connection string aplikasimu. Path relatif dihitung terhadap direktori kerja saat ini, yang berbeda antara terminal, IDE, dan proses production-mu. Database in-memory (:memory:) selalu baru setiap kali dibuka, dan ini menjebak orang yang mengharapkan datanya tersimpan.

Pemberian tanda kutip pada identifier juga penting. Nama tanpa tanda kutip tidak membedakan huruf besar kecil, tapi "User" dan "user" adalah identifier yang berbeda. Kalau kamu membuat tabel dengan nama yang diberi tanda kutip, kamu harus terus memberinya tanda kutip.

Pelanggaran constraint

SQLite menolak penulisan yang akan melanggar sebuah constraint. Pesan error-nya menyebutkan constraint yang mana:

Setiap kegagalan punya kode yang berbeda di baliknya (SQLITE_CONSTRAINT_UNIQUE, SQLITE_CONSTRAINT_CHECK, SQLITE_CONSTRAINT_NOTNULL). Perbaikannya hampir selalu ada di lapisan aplikasi: validasi input sebelum menulis, atau pakai INSERT ... ON CONFLICT untuk menangani duplikat dengan sengaja.

FOREIGN KEY constraint failed layak mendapat catatan khusus: foreign key nonaktif secara bawaan di SQLite. Kalau kamu tidak mengaktifkannya, referensi yang tidak valid masuk tanpa suara, lalu baru gagal belakangan saat kamu akhirnya menyalakan penegakannya. Atur pragma ini di setiap koneksi:

cannot start a transaction within a transaction

Kamu memanggil BEGIN saat sebuah transaksi masih terbuka. SQLite tidak mengizinkan transaksi bersarang, tapi mengizinkan savepoint bersarang, yang memberi efek yang sama:

Kalau ORM atau framework-mu yang mengelola transaksi, kemungkinan kamu menyuruhnya memulai transaksi dua kali. Periksa apakah autocommit aktif, dan apakah connection pool-mu memakai ulang koneksi yang masih punya transaksi terbuka.

disk I/O error (SQLITE_IOERR)

Sistem operasi menolak operasi baca atau tulis. Bisa karena disk penuh, gangguan filesystem jaringan, atau file-nya terhapus saat sedang dipakai SQLite. Hal pertama yang perlu diperiksa adalah df -h. Yang kedua adalah apakah database berada di tempat yang tidak stabil seperti NFS atau folder yang disinkronkan ke cloud. SQLite mengasumsikan filesystem POSIX lokal dengan fsync yang berfungsi. Kalau kamu tidak bisa memindahkannya, terimalah bahwa risiko kerusakan jadi lebih tinggi.

syntax error near "..."

Parser SQLite memberi tahu token mana yang membuatnya bingung. Perbaikannya biasanya ada tiga baris sebelum letak yang ditunjuk error: koma yang hilang, identifier tanpa tanda kutip yang bentrok dengan kata kunci, atau string dengan tanda kutip tunggal yang perlu di-escape ('it''s', bukan 'it's').

Pakai parameter binding (placeholder ?) untuk input pengguna, bukan membangun SQL dengan penyambungan string. Dengan begitu kamu terhindar dari satu kategori syntax error dan SQL injection sekaligus.

Daftar Periksa Diagnosis

Saat ada yang rusak di production, urutan ini mencakup sebagian besar kasus dalam waktu kurang dari semenit:

Lima pragma, lima jawaban. Digabung dengan kode error dari query yang gagal, kamu akan tahu masalahnya masuk kelompok yang mana dan halaman dokumentasi mana yang perlu dibuka berikutnya.

Itulah tur lengkapnya. Kamu sudah melangkah dari CREATE TABLE melewati join, index, transaksi, mode WAL, backup, dan sekarang jenis-jenis kegagalan yang muncul saat SQLite bertemu dunia nyata. Polanya berulang: transaksi yang singkat, foreign key yang diaktifkan, mode WAL, backup rutin, dan rasa hormat yang sehat terhadap PRAGMA integrity_check. Pertahankan kebiasaan itu, dan SQLite akan berjalan dengan tenang selama bertahun-tahun.

Pertanyaan yang sering diajukan

Kenapa SQLite menampilkan 'database is locked'?

Koneksi lain sedang memegang write lock dan koneksimu kehabisan waktu menunggu. Perbaikan yang biasa dilakukan adalah mengaktifkan mode WAL dengan PRAGMA journal_mode=WAL agar pembaca tidak memblokir penulis, menaikkan busy timeout dengan PRAGMA busy_timeout = 5000, dan memastikan transaksi segera di-commit, bukan dibiarkan terbuka.

Bagaimana cara memperbaiki 'attempt to write a readonly database' di SQLite?

Hampir selalu ini masalah izin filesystem, bukan masalah SQLite. User sistem operasi yang menjalankan prosesmu butuh akses tulis ke file database dan juga ke direktori tempat file itu berada (SQLite membuat file pendamping -journal atau -wal di sana). Periksa kepemilikan, mode bit, dan pastikan volume tidak di-mount sebagai read-only.

Apa arti 'database disk image is malformed'?

SQLite membaca byte yang tidak cocok dengan format yang diharapkannya, biasanya karena kerusakan akibat proses yang dimatikan paksa, disk yang buruk, atau menyalin file saat sedang terbuka. Jalankan PRAGMA integrity_check untuk memastikan, lalu pulihkan dengan .recover di CLI untuk menyalin apa yang masih bisa diselamatkan ke database baru. Restore dari backup lebih cepat kalau kamu punya.

Kenapa saya mendapat 'no such table' atau 'no such column'?

Kamu terhubung ke file database yang berbeda dari yang kamu kira, atau ada migrasi yang tidak berjalan. Periksa PRAGMA database_list untuk melihat path file yang benar-benar dibuka SQLite, dan .schema tablename untuk melihat kolom yang sebenarnya. Salah ketik dan perbedaan huruf besar kecil pada identifier juga sering terjadi: SQLite tidak membedakan huruf besar kecil untuk nama tanpa tanda kutip, tapi membedakannya untuk nama yang diberi tanda kutip.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai