Recovery mode does not work with AppSheet Database: no `_recoveryData` folder is created and pending changes are silently lost (sync reports "success" on desktop browser)

Summary

I tested the Recovery mode procedure described in the official documentation (“Errors and warnings during Sync”), and found that the behavior does not match the documentation when the data source is an AppSheet Database.

Official documentation:

On a desktop browser in particular, the sync appears to succeed, yet the pending changes are not written to the table and no _recoveryData folder is created. The data is simply lost. Because the error indicator disappears, app users have no way of noticing that anything was lost.

I have also reviewed the Audit History logs and included them below. If anyone has encountered the same behavior — or has had Recovery mode work correctly with an AppSheet Database — I would appreciate hearing about it.

Environment

  • Data source: AppSheet Database
  • Table: Table 1 (single table)
  • Clients tested: AppSheet app on iPhone / desktop browser
  • App definition version: 1.000136 (before the change — [Date] column present) → 1.000137 (after the change — [Date] column removed)
    • Note: the [Date] column existed in the earlier version, but was deleted, so it no longer exists in the database table.
  • Date tested: August 28, 2026

For context: I rarely use AppSheet Database as a data source in my normal work — I usually use Google Sheets. I chose AppSheet Database here specifically in order to test Recovery mode. As a result, I have not been able to confirm whether the same behavior occurs with Google Sheets as the data source.

Steps to reproduce (how I deliberately caused the sync error)

  1. Create an app with an AppSheet Database as its data source.
  2. Open the app on a client (the iOS app or a desktop browser) and leave a new form open. At this point the client holds the app definition from before the column deletion (1.000136).
  3. While the form is still open, delete the [Date] column from the AppSheet Database in the app editor.
  4. Regenerate and save in the app editor. The app definition version increments to 1.000137.
  5. The client has not synced, so it still holds the 1.000136 definition (in which the [Date] column still exists).
  6. On the client, fill in the still-open form and Save.
  7. Run a sync — it fails with a sync error.

At this point the client is in the following state:

  • The sync fails, so the changes cannot be sent, which in turn means the latest app definition cannot be retrieved.

Any further adds or edits made from the same device simply increase the number of pending changes, and no amount of syncing resolves it. Up to this point, the behavior matches what the documentation describes.

Results of testing Recovery mode

I followed the Recovery mode procedure in the official documentation.

① In the app editor, go to the [Manage] > [Deploy] pane and click [Switch to recovery mode]

② Retry the sync on the device where it was failing

The documentation states that the sync “should go through successfully” at this point. In practice, the behavior differed depending on the client.

iOS app

Switching to Recovery mode does not resolve the sync error. Repeated syncs continue to produce the same error.

Desktop browser

The sync appears to succeed — the red “!” indicator in the upper right disappears. However:

  • The added data is not written to the AppSheet Database table.
  • No _recoveryData folder is created in the app’s root folder.
  • Clicking [Return to normal mode] in the [Manage] > [Deploy] pane does not create the _recoveryData folder either.

In other words, the behavior described in the documentation — that the changes are saved to files in a recovery folder — does not occur, and the data is lost with no copy left anywhere.

It is worth noting that without switching to Recovery mode, the sync error is never resolved on the desktop browser either. This suggests that the sync going through was indeed caused by Recovery mode.

Findings from the Audit History

A note before this section: the Audit History analysis below was written with the help of my partner, Claude. I’ll admit this openly — there are parts of this analysis that I do not fully understand myself. I hope you’ll bear with me on that.

1. The failed row insert is rejected at the AppSheet Database layer

The Add row record has Result: Failure, and the error was logged as follows:

"Errors": "Unable to add row to table 'Table 1'. → Invalid request provided to AppSheet database"

The top frame of the stack trace is:

AsdbProvider.AsdbTable.InsertRowsInternalAsync(...) 
  in /src/Provider/AsdbProvider/AsdbTable.cs:line 674

AsdbProvider appears to refer to the AppSheet Database provider. This suggests that the request was not stopped at the sync layer, but rather reached the AppSheet Database row insert operation and was rejected there.

2. The submitted row data did reach the server

The RecordType: Start record for the same Add row operation contains the row values themselves:

"Row": [ "4", "<row id>", "2:47", "2:47", "2:47" ]
"RowSize": 35

There are five values, and these include a value corresponding to the deleted [Date] column (because the client created the row using the older definition). The total character count of the values matches the RowSize of 35, confirming that the data reached the server intact.

In other words, the data arrived at the server complete, was rejected, and then was not saved anywhere.

3. The sync as a whole is recorded as “success” even though the row insert failed

Approximately two seconds after Add row was logged with Result: Failure, App sync was logged within the same sync operation as follows:

"Errors": "Success"
"Result": "Success"

Both records share the same dataStamp (08/28/2026 17:47:26), which suggests they belong to the same sync request.

4. In that same sync, the app definition was delivered to the client successfully

The App sync record contains:

"localVersion": "1.000136"
"AppTemplateVersion": "1.000137"
"AppDefinitionChanged": true
"Table:Table 1": "LastModified:01/01/0001 00:00:00, NotModified:False"

The client is on 1.000136 while the server is on 1.000137, and AppDefinitionChanged is true. This means the downstream sync — server to client — completed successfully.

At the same time, there is no successful row operation associated with this sync. Only the downstream direction succeeded; the upstream changes were discarded without being processed.

As a result, the client is updated to the new definition and its pending changes are cleared, which means no trace of the data remains on the client side either.

5. The only place the data survives is the Add row Start record in the Audit History

As noted in point 2, the values themselves are recorded in the Audit History. However, there is no column name information, and the values include the deleted column, so they cannot be mapped directly onto the current table structure.

A possible explanation (speculation only)

The official documentation states that when there is an app definition mismatch, the message shown is This change cannot be applied because there is a newer version of your app. In this case, however, that version mismatch message never appeared. Instead, the request reached the AppSheet Database layer and was rejected with Invalid request provided to AppSheet database.

This leads me to wonder about the following possibility:

Could the _recoveryData write operation in Recovery mode be tied to the version mismatch detection path? If the data source is an AppSheet Database, the request may be rejected at the database layer before version mismatch detection ever runs — meaning the recovery file write is never invoked at all, and the changes are simply discarded.

This is purely inferred from the shape of the logs, so if anyone familiar with the internals can correct me, I would welcome it.

Why I consider this a problem

If the sync stops with a visible error, an administrator can notice that something is wrong, capture the changes with [Show Changes], and then run [Reset Changes]. There is at least an opportunity to save the data.

In the desktop browser case described here, however:

  • The sync succeeds
  • The error indicator disappears
  • Yet the data is written neither to the table nor to _recoveryData

The data is lost, and nobody notices the failure.

■For reference
Previous posts that appear to be similar to this one

Outstanding post, @イルカのえっちゃん!

@Jose_Arteaga, could you pass this on to someone on the development team?

Thank you, @Steve
I’m so pleased to hear you say that! :blush: