android data_error ai_generated true

android.database.sqlite.SQLiteException: Cannot read from cursor: column 'timestamp' has type TEXT but expected INTEGER (code 0)

ID: android/room-migration-ambiguous-column-type

Also available as: JSON · Markdown · 中文
87%Fix Rate
88%Confidence
1Evidence
2024-01-10First Seen

Version Compatibility

VersionStatusIntroducedDeprecatedNotes
Room 2.6.1 active — — —
Android 12 (API 31) active — — —
Android 11 (API 30) active — — —
Room 2.5.2 active — — —

Root Cause

Room migration script altered the schema without converting existing data types, causing a mismatch between the expected SQLite affinity (INTEGER) and the actual stored type (TEXT) in the column.

generic

中文

Room迁移脚本更改了架构但未转换现有数据类型,导致预期SQLite亲和类型(INTEGER)与列中实际存储类型(TEXT)不匹配。

Official Documentation

https://developer.android.com/training/data-storage/room/migrating-databases

Workarounds

  1. 90% success Write a manual migration that converts TEXT to INTEGER using CAST. Example in migration: ALTER TABLE my_table ADD COLUMN timestamp_temp INTEGER; UPDATE my_table SET timestamp_temp = CAST(timestamp AS INTEGER); ALTER TABLE my_table DROP COLUMN timestamp; ALTER TABLE my_table RENAME COLUMN timestamp_temp TO timestamp;
    Write a manual migration that converts TEXT to INTEGER using CAST. Example in migration: ALTER TABLE my_table ADD COLUMN timestamp_temp INTEGER; UPDATE my_table SET timestamp_temp = CAST(timestamp AS INTEGER); ALTER TABLE my_table DROP COLUMN timestamp; ALTER TABLE my_table RENAME COLUMN timestamp_temp TO timestamp;
  2. 85% success Use @TypeConverter to handle both types in the DAO. Example: @TypeConverter public static Long fromTimestamp(String value) { return value == null ? null : Long.parseLong(value); }
    Use @TypeConverter to handle both types in the DAO. Example: @TypeConverter public static Long fromTimestamp(String value) { return value == null ? null : Long.parseLong(value); }

中文步骤

  1. Write a manual migration that converts TEXT to INTEGER using CAST. Example in migration: ALTER TABLE my_table ADD COLUMN timestamp_temp INTEGER; UPDATE my_table SET timestamp_temp = CAST(timestamp AS INTEGER); ALTER TABLE my_table DROP COLUMN timestamp; ALTER TABLE my_table RENAME COLUMN timestamp_temp TO timestamp;
  2. Use @TypeConverter to handle both types in the DAO. Example: @TypeConverter public static Long fromTimestamp(String value) { return value == null ? null : Long.parseLong(value); }

Dead Ends

Common approaches that don't work:

  1. Delete app data and reinstall 80% fail

    This only works for development but destroys user data in production. The underlying migration issue is not fixed.

  2. Add fallbackToDestructiveMigration() to Room database builder 90% fail

    This drops the entire database on migration failure, losing all user data. It's a nuclear option that doesn't fix the type mismatch.