If you need technical support, submit a technical support request ticket. (See Contact Us)
Obtaining and Analyzing the Debug Logs
Synchronizing seems slow or comes to a halt over time
App is using too much memory, why?
Debugging Blocked Transactions
Causes of Blocked Transactions
Still stuck?
Obtaining and Analyzing the Debug Logs
To troubleshoot a peer-to-peer data sync issue, first determine the cause of the issue by obtaining and analyzing the database error and warning messages captured in the debug logs.Setting the Logs to Debug Level
As demonstrated in the following snippet, obtain the database debug logs before Ditto is initialized so that any potential issues related to the file system access and authentication background tasks that run during initialization are tracked. You want to begin gathering logs before Ditto is initialized in order to capture any potential issues with those two background tasks.Authentication
For OnlinePlayground and onlineWithAuthentication identities, the first thing that Ditto needs to do is authenticate to the Big Peer. Confirm that all devices share the same AppID by verifying that theapp_id
log line contains your AppID:
JSON
JSON
JSON
Incorrect APP ID
If the appID or token are incorrect, the following displays in the debug logs:JSON
JSON
- Log in to the Portal
- Go to your App.
- Copy the AppID and Playground Token and use it in your Ditto initialization.
Outdated certificate
JSON
ditto.auth.logout()
and reconnect to the Internet to get a new certificate. Alternatively, you can clear the local cache by reinstalling the mobile application or clearing the local persistence directory.
Authentication server unavailable
Shell
Shell
Shell
Ditto closing prematurely
If you see that Ditto is unable to sync, and see the log lines below, it’s possible that your ditto instance is being deallocated before it is able to synchronize with other peers. Ensure that the ditto instance is initialized and saved in a global variable that is long-lived for the duration of the application.Shell
Common mistakes
authenticationExpiringSoon
andauthenticationRequired
both need to be implemented according to the sample code.- Since callback objects are only invoked when Ditto initializes and the client authentication certificate expires, do not create subscriptions inside callbacks.
- Keep a strong reference to the AuthClient for the duration of the Ditto object, otherwise the auth handler will become garbage collected at an inappropriate time.
- Verify that your webhook provider name is correctly copied in the Ditto portal.
- The provider name given to the Ditto Client must match a provider name in the Portal (e.g.,
my-auth
).

Is your AuthClient becoming garbage collected?
Ensure that you keep a reference to the AuthClient in scope for the duration that Ditto is also active. You should attach the dittoAuth variable to the object so it does not get garbage collected. For example:C#
Syncing With Big Peer
A small peer sync with the Big Peer using a WebSocket connection. The debug logs will tell you each step to create a successful WebSocket connection to the big peer. First, the peer will discover the big peer and you’ll see aDiscovered
event.
JSON
ConnectionEstablished
event:
JSON
StreamFailed
or ConnectionEnded
or any errors related to WebSocket connection with the Big Peer, there is likely an error in the Big Peer subscription server. For troubleshooting help, contact Ditto support.
Corrupted certificate
If your certificate chain is corrupted, you will see the following.JSON
JSON
phy started
.
The pkSOME_BYTES identifer displays the public key to the Big Peer instance that
a Small Peer WebSocket connection has temporary sync access.
Note that the following snippet is merely an example; the pkSOME_BYTES
identifer is not a guaranteed static variable.
JSON
JSON
Permissions and Subscriptions
For the Small Peer to have an active subscription to read and write to other peers, it must first be authorized access by a Big Peer. If the Small Peer does not have permissions to access database replication, it cannot subscribe to its collections to read and write.Permissions
Given this, before you check the Small Peer’s active read-write subscriptions, confirm that the Small Peer has permissions to access the database.JSON
JSON
Subscriptions
Now that default permissions are verified, confirm that the Big Peer is connected to a Small Peer and the local-to-global database replication task is running. Ditto prints a list of all the queries that the peer is currently subscribed to.JSON
__
) before the collection name; for example, the following default internal __presence
subscription:
JSON
JSON
JSON
JSON
- Do your permissions match your subscriptions? If you do not have permission to subscribe to data, it will not sync to the device.
- Are you subscribing to what you expect to see?
- Do you have more subscriptions than you expect to have?
- Do your live queries match the subscriptions?
Query Parsing Errors
ParseError
can be printed in the debug logs when there is a problem with your query. For example, if you create a subscription in Swift that is the empty string, you will see a ParseError
in the logs.
Writes
If a Write is made to the local database, the following debugging messages appear:JSON
JSON
JSON
JSON
JSON
Did your device connect to the internet?
OnlinePlayground
applications must connect to the Big Peer first before going offline. Read more about online playground.
Do you have a firewall or proxy enabled that is blocking Ditto’s connection to the Big Peer?
A proxy may either either block connections or cause errors in the log by substituting its own TLS certificate:invalid certificate: UnknownIssuer
. If you see this log message you will either need to get Ditto unblocked or add the CA certificate to the Small Peer’s trusted certificate store.
Verify that you can reach the following endpoints. You should see the output exactly as written below:
JSON
JSON
Connection issues
If you are unable to see connections over particular transports, first ensure you are following the SDK Setup guide for your language. After you verify that your app is set up correctly, if connection issues continue follow these debugging steps.Bluetooth
- Turn Use Location on
- Turn Bluetooth Scanning on
- Are permissions set correctly? See
- Go to your OS-level permissions for Bluetooth and clear the app permissions for your application.
- Delete the app, install it again, and open it. Does it ask for Bluetooth permissions?
Apple Wireless Direct Link, P2P-Wifi, Wifi Aware
- Go to your OS-level permissions and clear the app permissions for your application.
- Delete the app, install it again, and open it. Does it ask for location permissions?
- If you are using a custom
Local Area Network (LAN)
- Are permissions set correctly? See
- Are both devices connected to the same WiFi network?
- Check your router settings and see the
- If your device has VPN enabled, then peers can fail to communicate. Ensure that your VPN supports UDP multicasting.
Debugging Blocked Transactions
This section only discusses blocked transactions on native platforms (e.g. iOS, Android, Windows, Linux). Ditto in web browsers operates sufficiently differently and isn’t covered here.
- Unresponsive UI: an interaction might try to update a document, but is blocked by an existing write transaction
- Slow sync: new updates cannot be integrated into the store, since they’re blocked by another write transaction
Did your certificate expire and fail to refresh?
When usingOnlineWithAuthentication
,
Send a POST request with a JSON stringified body to your server to ensure that Ditto Server successfully sends POST requests to your authentication server.
- authenticationExpiringSoon
- Since callback objects are only invoked when Ditto initializes and the client authentication certificate expires, do not create subscriptions inside callbacks.
- Keep a strong reference to the AuthClient for the duration of the Ditto object, otherwise the auth handler will become garbage collected at an inappropriate time.
Verify that your webhook provider name is correctly copied in the Ditto portal
The provider name given to the Ditto Client must match a provider name in the Portal (e.g., my-auth).Is your AuthClient becoming garbage collected?
Ensure that you keep a reference to the AuthClient in scope for the duration that Ditto is also active. You should attach the dittoAuth variable to the object so it does not get garbage collected. For example:psuedocode
Bluetooth
- Turn Use Location on
- Turn Bluetooth Scanning on
- Are permissions set correctly? From SDK Setup Guides, refer to the installation article for your language
- Go to your OS-level permissions for Bluetooth and clear the app permissions for your application.
- Delete the app, install it again, and open it. Does it ask for Bluetooth permissions?
- Android only: are you calling
ditto.refreshPermissions()
?
Apple Wireless Direct Link, P2P-Wifi, Wifi Aware
- Are permissions set correctly? (From SDK Setup Guides, refer to the installation article for your language)
- Go to your OS-level permissions and clear the app permissions for your application.
- Delete the app, install it again, and open it. Does it ask for location permissions?
- If you are using a custom
TransportConfig
, make sure you have enabled all peer-to-peer transports usingenableAllPeerToPeer()
.
Local Area Network (LAN)
- Are permissions set correctly? From SDK Setup Guides, refer to the installation article for your language)
- Are both devices connected to the same WiFi network?
- Check your router settings and see Lan Optimizations
- If your device has VPN enabled, then peers can fail to communicate. Ensure that your VPN supports UDP multicasting.
Synchronization seems slow, or comes to a halt over time
- Ensure that you are only creating a fixed number of live queries, with a smaller amount of data.
- Avoid using
LIMIT
orORDER BY
with mutable fields in subscription queries. See Stateful Subscription Performance Guidelines for details. - Evict irrelevant data. You can evict all irrelevant once per day
- Turn off verbose logging. Verbose logging can slow down replication considerably, especially with thousands of documents. Hence, it could look like that sync is stalling, but that can be indistinguishable from the logging mechanism slowing down ditto because it is trying to write too many lines.
- Look at the size of your ditto directory. Is it very large? Large databases will be slower. Try to query less data.
App is using too much memory, why?
- Use profiling tools for your platform to better understand where the memory leak may be occurring.
- Ensure you are not loading too much data into memory at once. Ditto is designed to work with large datasets, but you should only load the data you need at any given time.
- A common issue we see in reactive apps is a failure to dispose of resources as
conditions change. Your app could create a large accumulation of publishers that
infinitely grow. Every liveQuery and subscription in ditto must be explicitly
stopped using the
stop
orcancel
API. See syncing data for more information.
Debugging Blocked Transactions
This section only discusses blocked transactions on native platforms (e.g. iOS, Android, Windows, Linux). Ditto in web browsers operates sufficiently differently and isn’t covered here.
- Unresponsive UI: an interaction might try to update a document, but is blocked by an existing write transaction
- Slow sync: new updates cannot be integrated into the store, since they’re blocked by another write transaction
What is a “blocked” transaction?
At any given time, there can be only one write transaction. Any subsequent attempts to open another write transaction will become blocked until the existing write transaction finishes.Read vs. Write Transactions
Read transactions operate differently to write transactions. Read transactions cannot be blocked and can run in parallel with write transactions. Read transactions don’t block each other, don’t block write transactions, and aren’t blocked by write transactions. If a write transaction is blocked, Ditto will log a message with increasing severity every 10s.Time (t) a transaction has been blocked | Log Level |
---|---|
t ≤ 30s | DEBUG |
31s < t ≤ 120s | WARN |
120s < t | ERROR |
Reading the Logs
If a write transaction is blocked, the device logs will look something like the following. In this example we can see a write transaction was blocked for a total of 150s (or 2.5 minutes).
Originators
The three values you’ll see for originator and blocked_by are:Originator / Blocked By | Description |
---|---|
”User” | Any user-level API which modifies data. |
”Internal” | An internal job (presence data, DB maintenance, etc.). |
”Replication” | Updating the store with data received via replication. |