Skip to content

App freezes with openPowerSyncWithGRDB + connect(), and perhaps other cases with connect() and watch() #125

Description

@vinayh

Hello,

I've been encountering this issue and after some extensive debugging, suspect it may be related to the Swift SDK.

openPowerSyncWithGRDB() combined with connect() causes the app to permanently freeze (main thread blocked indefinitely), regardless of how many watch() calls are active — even zero. The equivalent setup using PowerSyncDatabase() (Kotlin-managed pool) works correctly with 8 concurrent watches + connect().

The SDK's own test testGRDBUpdatesFromPowerSync uses ValueObservation + openPowerSyncWithGRDB but never calls connect(), so this combination is not covered by the test suite.

Environment

  • powersync-swift: 1.13.1
  • powersync-sqlite-core-swift: 0.4.12
  • GRDB: 7.10.0
  • Platform: iOS 18 (iPhone, iPad), macOS 15

Reproduction

import PowerSync
import PowerSyncGRDB
import GRDB

let schema = Schema(
    Table(name: "table_a", columns: [.text("name")])
)

// -- GRDB pool path (freezes) --
let appSupport = FileManager.default.urls(
    for: .applicationSupportDirectory, in: .userDomainMask
).first!.appendingPathComponent("databases")
try FileManager.default.createDirectory(at: appSupport, withIntermediateDirectories: true)
let dbPath = appSupport.appendingPathComponent("test.sqlite").path

var config = Configuration()
try config.configurePowerSync(schema: schema)
let pool = try DatabasePool(path: dbPath, configuration: config)
let db = openPowerSyncWithGRDB(
    pool: pool,
    schema: schema,
    identifier: "test-db"
)

struct MyConnector: PowerSyncBackendConnectorProtocol {
    func fetchCredentials() async throws -> PowerSyncCredentials? {
        // Replace with your PowerSync instance credentials
        PowerSyncCredentials(
            endpoint: "https://YOUR_INSTANCE.powersync.journeyapps.com",
            token: "YOUR_JWT_TOKEN"
        )
    }
    func uploadData(database: any PowerSyncDatabaseProtocol) async throws {}
}

// This alone freezes — no watch() calls needed
Task.detached {
    try await db.connect(connector: MyConnector())
}
// App freezes after connect() completes its first sync cycle

Configurations tested

Configuration Result
openPowerSyncWithGRDB + connect() + 0 watches Freeze
openPowerSyncWithGRDB + connect() + GRDB ValueObservation Freeze
openPowerSyncWithGRDB + no connect() + GRDB ValueObservation Stable (no sync, no data)
openPowerSyncWithGRDB + connect() + 8 db.watch() streams Freeze
PowerSyncDatabase() + connect() + 8 db.watch() streams Stable

The freeze occurs after connect() completes its first sync cycle. No crash, no error, no timeout — the app simply hangs. connect() through the GRDB pool is the sole trigger.

Context

This was initially misdiagnosed as a broader Kotlin dispatcher serialization issue. Extensive testing (multiple watches, readTransaction batching, separate GRDB connections, SDK version upgrades) all showed freezes. It was later determined that the multi-watch freeze was specific to powersync-sqlite-core-swift 0.4.11 and was resolved in 0.4.12. The openPowerSyncWithGRDB + connect() freeze persists independently on 0.4.12.

Expected behavior

openPowerSyncWithGRDB should work with connect() the same way PowerSyncDatabase() does. The GRDB pool path is advertised as supporting concurrent readers, but connect() through it freezes regardless of other activity.

Workaround

Use PowerSyncDatabase(schema:, dbFilename:) instead of openPowerSyncWithGRDB(). This uses the Kotlin-managed connection pool and works correctly with connect() + multiple watches.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions