Skip to content

apply: a failure with no message reports only "Unable to apply payload changes" #83

Description

@andinux

Summary

When cloudsync_payload_apply fails and no error message reached it, the generic fallback is all the caller gets — the return code and SQLSTATE are dropped from the text. A lock, busy or serialization failure then looks exactly like any other apply error.

src/cloudsync.c:4690:

cloudsync_set_error(data, fail_message[0] ? fail_message : "Unable to apply payload changes", rc);

fail_message is captured at :4662/:4675 from cloudsync_errmsg(data), and fail_sqlstate at :4663. When the message is empty the fallback carries neither.

How it showed up

A CI Peer Test failure on one platform (run 36431727289), surfaced by the server as:

{"status":"422","code":"database_cloudsync_not_ready",
 "detail":"CloudSync is not available, ready, or correctly configured on database: Unable to apply payload changes"}

It took several steps to establish that this was a transient concurrency failure rather than a version incompatibility or a code regression — a re-run passed with no change. The message on its own gave no way to tell. Every matrix leg targets the same integration database and Peer Test runs five threads, so concurrent applies against one tenant are routine there.

Had the code been in the message, the class of failure would have been visible immediately: on PostgreSQL a 40001 says serialization failure, on SQLite a 5/6 says busy or locked.

Suggested change

cloudsync_set_error takes a plain string with no formatting variant, so the message has to be built first:

char fallback[128];
if (!fail_message[0]) {
    // No message reached us with the failure, so carry the codes instead: without
    // them a lock, busy or serialization failure is indistinguishable from any
    // other apply error in a server log.
    if (fail_sqlstate)
        snprintf(fallback, sizeof(fallback), "Unable to apply payload changes (code %d, sqlstate %d)", rc, fail_sqlstate);
    else
        snprintf(fallback, sizeof(fallback), "Unable to apply payload changes (code %d)", rc);
}
cloudsync_set_error(data, fail_message[0] ? fail_message : fallback, rc);

The literal is not matched anywhere in the cloudsync repo, so extending it does not break server-side handling.

Notes

This is diagnostic only. It does not fix whatever returns a non-OK fail_rc with cloudsync_errmsg() empty — it makes the next occurrence identifiable rather than requiring an investigation. Finding and fixing that path is the real follow-up, and the code in the message is how you would identify it.

There is an alternative place for it. rc is already passed to cloudsync_set_error as err_code, so it is not lost inside the extension — it is dropped on the way out through the server's HTTP error. Surfacing the code alongside detail in cloudsync would fix the same diagnosability gap without touching the extension, and would help every error that travels that path, not just this one. Worth deciding which side should own it before implementing.

Introduced with the apply cleanup in #65.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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