laurent22/joplin · error · Error

Could not access data on server "${options.path()}"

Error message

Could not access data on server "${options.path()}"

What it means

Thrown by SyncTargetJoplinServer.checkConfig during a write/read round-trip test: it put('testing.txt', 'testing') then get('testing.txt') and the returned content is not 'testing'. This catches silent data corruption or server-side rewriting (e.g. a proxy that mangles bodies) that stat-only checks would miss.

Source

Thrown at packages/lib/SyncTargetJoplinServer.ts:133

				if (r) {
					const parsed = JSON.parse(r);
					if (parsed) {
						output.ok = true;
						return output;
					}
				}
			} catch (error) {
				// Ignore because we'll use the next test to check for sure if it
				// works or not.
				staticLogger.warn('Could not fetch or parse info.json:', error);
			}

			// This is a more generic test, which writes a file and tries to read it
			// back.
			try {
				await fileApi.put('testing.txt', 'testing');
				const result = await fileApi.get('testing.txt');
				if (result !== 'testing') throw new Error(`Could not access data on server "${options.path()}"`);
				await fileApi.delete('testing.txt');
				output.ok = true;
			} catch (error) {
				output.errorMessage = error.message;
				if (error.code) output.errorMessage += ` (Code ${error.code})`;
			}
		} finally {
			fileApi.requestRepeatCount_ = previousRequestRepeatCount;
		}

		return output;
	}

	protected async initFileApi() {
		return initFileApi(SyncTargetJoplinServer.id(), this.logger(), {
			path: () => Setting.value('sync.9.path'),
			userContentPath: () => Setting.value('sync.9.userContentPath'),
			username: () => Setting.value('sync.9.username'),

View on GitHub (pinned to 2654b33620)

Solutions

  1. Verify the server URL and base path in sync settings point to the real Joplin Server endpoint.
  2. Check any reverse proxy (nginx, Cloudflare) for response body rewriting or charset overrides — disable auto-minify / Rocket Loader etc.
  3. Ensure reads and writes resolve to the same path (no path-rewrite rules that differ for PUT vs GET).
  4. Try a direct connection to the Joplin Server without the proxy to isolate the cause.

Example fix

# before: Cloudflare in front of Joplin Server, rewriting bodies
# after: in Cloudflare, disable 'Auto Minify' and 'Rocket Loader' for the Joplin Server route,
# and confirm the sync URL is https://server/api/files/...
Defensive patterns

Strategy: try-catch

Validate before calling

// Outside checkConfig, you can pre-flight with a manual round-trip.
await fileApi.put('probe.txt', 'x');
const back = await fileApi.get('probe.txt');
if (back !== 'x') throw new Error('Server is rewriting payloads — check reverse proxy');
await fileApi.delete('probe.txt');

Type guard

const isPassthroughPayload = (sent, received) => sent === received;

Try / catch

try { await SyncTargetJoplinServer.checkConfig(options); }
catch (e) { if (/Could not access data on server/.test(e.message)) { /* inspect proxy / path config */ } else throw e; }

Prevention

When it happens

Trigger: checkConfig() puts 'testing.txt', reads it back, and `result !== 'testing'`. Caused by an intermediate proxy rewriting content, a misconfigured Joplin Server returning HTML errors as 200, or a server that stores content under a different path than it reads.

Common situations: Server URL points to a reverse proxy that injects boilerplate; wrong base path so reads hit a different namespace than writes; server is actually a different Joplin Server instance than expected; encoding/charset conversion.

Related errors


AI-assisted analysis of laurent22/joplin@2654b33620 (2026-08-12). Data as JSON: /api/errors/45cc9b3a79e111ec. Report an issue: GitHub.