Skip to content

fix: capacitor iOS Buffer read error#933

Merged
stevensJourney merged 3 commits intomainfrom
fix-capacitor-buffers
Apr 22, 2026
Merged

fix: capacitor iOS Buffer read error#933
stevensJourney merged 3 commits intomainfrom
fix-capacitor-buffers

Conversation

@stevensJourney
Copy link
Copy Markdown
Collaborator

This is an alternative solution to the one provided in #905.

Overview

Users have reported errors of the form

Run: failed(message: "Error in reading buffer")

When using the PowerSync Capacitor SDK to connect to a PowerSync service.

Background

The PowerSync SDK sync stream client sends binary payloads from the PowerSync service to the PowerSync Rust core by making SQL queries of the form

execute('SELECT powersync_control(?, ?)', ['line-binary', payload]))

The RSocket client we use to connect to the PowerSync service requires a polyfill for Buffer which is provided and bundled in the @powersync/common package. This results in the payload above being an instance of the polyfilled Buffer.

The Capacitor Community SQLite lib accepts buffer payloads as a dictionary mapping of numerical array indexes to numerical byte values.

/// Parameter parsing logic in the `run`/`execute` method.
                        } else if let obj = value as? [String: Any] {
                            if var keys = Array(obj.keys) as? [String] {
                                if #available(iOS 15.0, *) {
                                    keys.sort(using: .localizedStandard)
                                    var valuesArr: [UInt8] = []
                                    for key in keys {
                                        if let mVal = obj[key] {
                                            if let iVal = mVal as? Int {
                                                valuesArr.append(UInt8(iVal))
                                            } else {
                                                let msg: String = "Error in reading buffer"
                                                throw CapacitorSQLiteError.failed(message: msg)
                                            }
                                        } else {
                                            let msg: String = "Error in reading buffer"
                                            throw CapacitorSQLiteError.failed(message: msg)
                                        }
                                    }
                                    val.append(valuesArr)
                                } else {
                                    let msg: String = "Error buffer sorted not implemented"
                                    throw CapacitorSQLiteError.failed(message: msg)

                                }
                            }

The above parsing logic will fail with a Error in reading buffer error if either:

  • a value associated with a key cannot be converted to an Int type
  • a value associated with a key is nil

The Buffer polyfil in @powersync/common defines a few additional fields in it's implementation, which are passed through the native bridge to the Swift SQLite layer. These additional parameters don't meet the above parsing requirements, which cause the error above.

For example: in the polyfil, we see an parent member being declared.

		Object.defineProperty(Buffer.prototype, 'parent', {
		  enumerable: true,
		  get: function () {
		    if (!Buffer.isBuffer(this)) return undefined
		    return this.buffer
		  }
		});

When debugging the Swift parsing logic, we can see this value propagates from JS to Swift

Notice the value for key is parent which has a value which could not be cast to a numerical Int value
image

The Fix

Only the Buffer polyfil contains these incompatible member values. We can create a Uint8Array view over the Buffer and pass that to the SQLite lib instead. This should have minimal overhead.

Testing

For some reason, I have not been able to reproduce this issue previously... On the current main branch with an updated capacitor package from 7.4.x to 7.6.x I have been able to reproduce the issue.

I've confirmed manually that the example-capacitor demo connects and syncs correctly to a PowerSync service after applying these changes.

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 22, 2026

🦋 Changeset detected

Latest commit: 152ea89

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@powersync/capacitor Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@stevensJourney stevensJourney marked this pull request as ready for review April 22, 2026 07:44
@stevensJourney stevensJourney requested a review from simolus3 April 22, 2026 07:44
Copy link
Copy Markdown
Contributor

@rkistner rkistner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of interest, is it RSocket that uses the Buffer polyfill? It would be great if it would use plain Uint8Array natively, but that's probably not easy to change. Looks like there is an open issue for that, but hasn't seen much activity lately: rsocket/rsocket-js#273

Regardless of that, the Capacitor Uint8Array handling is likely still quite slow, but using a native Uint8Array is a step in the right direction at least.

@stevensJourney
Copy link
Copy Markdown
Collaborator Author

Out of interest, is it RSocket that uses the Buffer polyfill? It would be great if it would use plain Uint8Array natively, but that's probably not easy to change. Looks like there is an open issue for that, but hasn't seen much activity lately: rsocket/rsocket-js#273

Yeah that is the case. We might be able to override Buffer to Uint8Array in the bundling process - but I'm not sure what kinds of trouble that could cause.

Regardless of that, the Capacitor Uint8Array handling is likely still quite slow, but using a native Uint8Array is a step in the right direction at least.

Indeed 😄

@stevensJourney stevensJourney merged commit 26c2c24 into main Apr 22, 2026
11 checks passed
@stevensJourney stevensJourney deleted the fix-capacitor-buffers branch April 22, 2026 08:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants