Skip to content

PowerSync sync intermittently stalls after token expiry; only clearing app storage + re-login recovers #1265

Description

@nico-fioretti

Summary

On a self-hosted setup the Android app intermittently fails to finish syncing when opened. When it happens, the only reliable recovery is clearing the app storage and logging in again — restarting the app or waiting does not help. It is intermittent, which points at accumulated client state rather than every launch.

Environment

  • wger server 2.7.0a1 (self-hosted, docker), PowerSync service journeyapps/powersync-service:latest
  • App client: powersync-dart-core/2.3.0 (Dart 3.12.2, Android)
  • Single user

Server-side evidence (all infra healthy)

I went through the self-hosted stack and ruled infra out:

The only recurring error in the PowerSync logs is the auth token expiring:

```
errorData: {code: PSYNC_S2103, description: "JWT has expired", status: 401}, route: /sync/stream
tokenDetails: payload {sub: 2, iat: ..., aud: powersync, exp: iat+600}
```

The server-issued PowerSync JWT has a 600 s lifetime, so the client must refresh it every ~10 min. In the instance I captured, the 401 self-healed: right after PSYNC_S2103 there is a fresh POST /sync/streamSync stream started → new checkpoint → Sync stream complete. So the normal refresh path works.

Hypothesis

The permanent stalls appear to be the subset where, after the token expires (e.g. the app resumes from the background more than 10 min later), the client does not recover the stream — the credential refresh / reconnect after PSYNC_S2103 occasionally fails, and it stays down until a full storage-clear + re-login rebuilds the whole token chain. I could not capture the fatal stall directly in the server logs (the captured expiry recovered), so this part is inferred from the symptom (only re-login fixes it) rather than proven server-side.

Questions / asks

  1. On PSYNC_S2103 (token expired) mid-stream, does the connector reliably call fetchCredentials() and reconnect, or can it get wedged holding a stale token until the local state is wiped?
  2. Would it help to proactively refresh the PowerSync token before expiry given the short 600 s server default?

Related

I opened wger-project/wger#2428 to make the server token lifetime configurable (default unchanged at 600 s). Raising it is a palliative that reduces how often the client sits with an expired token on resume, but the underlying client recovery on PSYNC_S2103 is the actual fix and belongs here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions