actualbudget/actual · error · Error

network-failure

network-failure

Error message

Authentication failed: server offline or unreachable

What it means

During init(), after validating the stored token, the code checks user.offline. If the server reports itself offline (or unreachable when validating), the token is cleared and this error is thrown with code 'network-failure'. It signals the sync server could not be reached or is in an offline state, not a bad credential.

Source

Thrown at packages/loot-core/src/server/main.ts:312

    if ('sessionToken' in config && config.sessionToken) {
      // Session token authentication
      await runHandler(handlers['subscribe-set-token'], {
        token: config.sessionToken,
      });
      // Validate the token
      const user = await runHandler(handlers['subscribe-get-user'], undefined);
      if (!user || user.tokenExpired === true) {
        // Clear invalid token
        await runHandler(handlers['subscribe-set-token'], { token: '' });
        throw withErrorCode(
          new Error('Authentication failed: invalid or expired session token'),
          'token-expired',
        );
      }
      if (user.offline === true) {
        // Clear token since we can't validate
        await runHandler(handlers['subscribe-set-token'], { token: '' });
        throw withErrorCode(
          new Error('Authentication failed: server offline or unreachable'),
          'network-failure',
        );
      }
    } else if ('password' in config && config.password) {
      const result = await runHandler(handlers['subscribe-sign-in'], {
        password: config.password,
      });
      if (result?.error) {
        // `result.error` is already a machine-readable slug (e.g.
        // 'invalid-password', 'network-failure')
        throw withErrorCode(
          new Error(`Authentication failed: ${result.error}`),
          result.error,
        );
      }
    }
  } else {

View on GitHub (pinned to d4334cb6e6)

Solutions

  1. Check the sync server is running and reachable at the configured URL (curl the server health endpoint)
  2. Correct the server URL in the client configuration
  3. Check network/firewall/proxy rules between client and server
  4. If the server intentionally runs offline, reconfigure the client for local-only use or restore server connectivity

Example fix

// before
await init({ URL: 'http://localhost:5007', TOKEN }); // wrong port
// after
await init({ URL: 'http://localhost:5006', TOKEN }); // correct sync-server port
Defensive patterns

Strategy: retry

Validate before calling

// Probe the server before init
const res = await fetch(`${serverUrl}/health`, { method: 'GET' }).catch(() => null);
if (!res || !res.ok) {
  throw new Error(`Sync server unreachable at ${serverUrl}`);
}

Type guard

function isNetworkFailureError(e: unknown): e is Error & { code: 'network-failure' } {
  return e instanceof Error && (e as { code?: string }).code === 'network-failure';
}

Try / catch

try {
  await init({ URL: serverUrl, TOKEN });
} catch (e) {
  if (isNetworkFailureError(e)) {
    await delay(2000);
    return init({ URL: serverUrl, TOKEN }); // single bounded retry after connectivity check
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling init() with a token-based config when 'subscribe-get-user' returns offline:true — server down, wrong URL/port, DNS failure, or the server explicitly set to offline mode.

Common situations: Sync server not started or crashed; misconfigured server URL in client settings; firewall/proxy blocking the server; self-hosted server behind an unreachable host in remote environments.

Understand the failure class

Related errors


AI-assisted analysis of actualbudget/actual@d4334cb6e6 (2026-08-29). Data as JSON: /api/errors/062e3696d72c9db3. Report an issue: GitHub.