laurent22/joplin · error · Error

All potential ports are in use or not available.

Error message

All potential ports are in use or not available.

What it means

Thrown by ClipperServer.findAvailablePort() after 10000 iterations of randomClipperPort each calling tcp-port-used.check. If every candidate port is reported in use, the clipper server cannot bind and the API is unreachable. startPort seeds the range per environment (dev vs prod).

Source

Thrown at packages/lib/ClipperServer.ts:109

		if (this.port_ === v) return;
		this.port_ = v;
		this.dispatch({
			type: 'CLIPPER_SERVER_SET',
			port: v,
		});
	}

	public async findAvailablePort(): Promise<number> {
		const tcpPortUsed = require('tcp-port-used');

		let state = null;
		for (let i = 0; i < 10000; i++) {
			state = randomClipperPort(state, Setting.value('env'));
			const inUse = await tcpPortUsed.check(state.port);
			if (!inUse) return state.port;
		}

		throw new Error('All potential ports are in use or not available.');
	}

	public async isRunning() {
		const tcpPortUsed = require('tcp-port-used');
		const port = Setting.value('api.port') ? Setting.value('api.port') : startPort(Setting.value('env'));
		const inUse = await tcpPortUsed.check(port);
		return inUse ? port : 0;
	}

	public async start() {
		if (!this.enabled()) throw new Error('Cannot start clipper server because it is disabled');

		this.setPort(null);

		this.setStartState(StartState.Starting);

		const settingPort = Setting.value('api.port');

View on GitHub (pinned to 2654b33620)

Solutions

  1. Free up ports: close other Joplin instances and check `lsof -i` / `netstat` for listeners in the clipper port range.
  2. Restart the machine if ephemeral ports are exhausted (TIME_WAIT buildup).
  3. Disable any security software that reserves ephemeral ranges and retry.
  4. If persistent, file an issue — tcp-port-used may be misreporting on your platform.

Example fix

// before: findAvailablePort() loops forever then throws
// after (manual workaround)
// 1. lsof -i :41184  (or the configured clipper port range)
// 2. kill the conflicting process, then retry starting the clipper server
Defensive patterns

Strategy: retry

Validate before calling

// Probe a specific candidate port before relying on findAvailablePort.
const tcpPortUsed = require('tcp-port-used');
const isFree = async (port) => !(await tcpPortUsed.check(port));

Type guard

const isPortNumber = (p) => Number.isInteger(p) && p > 0 && p < 65536;

Try / catch

try { await clipperServer.findAvailablePort(); }
catch (e) { if (/All potential ports are in use/.test(e.message)) { /* free ports or report to user; do not blind-retry */ } else throw e; }

Prevention

When it happens

Trigger: findAvailablePort() loops 10000 times, each tcpPortUsed.check(state.port) returns true, exhausting the search space.

Common situations: Heavily loaded machine with many listeners; firewall/security software holding ephemeral ports; another Joplin instance already running; tcp-port-used falsely reporting in use due to permission issues.

Related errors


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