{"record":{"id":"921a6e98ea8e1231","repo":"laurent22/joplin","slug":"all-potential-ports-are-in-use-or-not-available","errorCode":null,"errorMessage":"All potential ports are in use or not available.","messagePattern":"All potential ports are in use or not available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/lib/ClipperServer.ts","lineNumber":109,"sourceCode":"\t\tif (this.port_ === v) return;\n\t\tthis.port_ = v;\n\t\tthis.dispatch({\n\t\t\ttype: 'CLIPPER_SERVER_SET',\n\t\t\tport: v,\n\t\t});\n\t}\n\n\tpublic async findAvailablePort(): Promise<number> {\n\t\tconst tcpPortUsed = require('tcp-port-used');\n\n\t\tlet state = null;\n\t\tfor (let i = 0; i < 10000; i++) {\n\t\t\tstate = randomClipperPort(state, Setting.value('env'));\n\t\t\tconst inUse = await tcpPortUsed.check(state.port);\n\t\t\tif (!inUse) return state.port;\n\t\t}\n\n\t\tthrow new Error('All potential ports are in use or not available.');\n\t}\n\n\tpublic async isRunning() {\n\t\tconst tcpPortUsed = require('tcp-port-used');\n\t\tconst port = Setting.value('api.port') ? Setting.value('api.port') : startPort(Setting.value('env'));\n\t\tconst inUse = await tcpPortUsed.check(port);\n\t\treturn inUse ? port : 0;\n\t}\n\n\tpublic async start() {\n\t\tif (!this.enabled()) throw new Error('Cannot start clipper server because it is disabled');\n\n\t\tthis.setPort(null);\n\n\t\tthis.setStartState(StartState.Starting);\n\n\t\tconst settingPort = Setting.value('api.port');\n","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/ClipperServer.ts#L91-L127","documentation":"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).","triggerScenarios":"findAvailablePort() loops 10000 times, each tcpPortUsed.check(state.port) returns true, exhausting the search space.","commonSituations":"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.","solutions":["Free up ports: close other Joplin instances and check `lsof -i` / `netstat` for listeners in the clipper port range.","Restart the machine if ephemeral ports are exhausted (TIME_WAIT buildup).","Disable any security software that reserves ephemeral ranges and retry.","If persistent, file an issue — tcp-port-used may be misreporting on your platform."],"exampleFix":"// before: findAvailablePort() loops forever then throws\n// after (manual workaround)\n// 1. lsof -i :41184  (or the configured clipper port range)\n// 2. kill the conflicting process, then retry starting the clipper server","handlingStrategy":"retry","validationCode":"// Probe a specific candidate port before relying on findAvailablePort.\nconst tcpPortUsed = require('tcp-port-used');\nconst isFree = async (port) => !(await tcpPortUsed.check(port));","typeGuard":"const isPortNumber = (p) => Number.isInteger(p) && p > 0 && p < 65536;","tryCatchPattern":"try { await clipperServer.findAvailablePort(); }\ncatch (e) { if (/All potential ports are in use/.test(e.message)) { /* free ports or report to user; do not blind-retry */ } else throw e; }","preventionTips":["Avoid running many listeners concurrently on the same host; close clipper servers you no longer need.","If the issue persists, suspect false positives from tcp-port-used on your OS and report it rather than raising the loop ceiling."],"tags":["network","clipper-server","port-binding","runtime"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}