{"record":{"id":"aec6cd997de0540e","repo":"laurent22/joplin","slug":"unknown-profile-version-most-likely-this-is-an-ol","errorCode":null,"errorMessage":"Unknown profile version. Most likely this is an old version of Joplin, while the profile was created by a newer version. Please upgrade Joplin at https://joplinapp.org and try again.\nJoplin version: ${shim.appVersion()}\nProfile version: ${fromVersion}\nExpected version: ${existingDatabaseVersions[existingDatabaseVersions.length - 1]}","messagePattern":"Unknown profile version\\. Most likely this is an old version of Joplin, while the profile was created by a newer version\\. Please upgrade Joplin at https://joplinapp\\.org and try again\\.\nJoplin version: (.+?)\nProfile version: (.+?)\nExpected version: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/lib/JoplinDatabase.ts","lineNumber":410,"sourceCode":"\t\t// IMPORTANT:\n\t\t//\n\t\t// Whenever adding a new database property, some additional logic might be needed\n\t\t// in the synchronizer to handle this property. For example, when adding a property\n\t\t// that should have a default value, existing remote items will not have this\n\t\t// default value and thus might cause problems. In that case, the default value\n\t\t// must be set in the synchronizer too.\n\n\t\t// Note: v16 and v17 don't do anything. They were used to debug an issue.\n\t\tconst existingDatabaseVersions = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41];\n\n\t\tfor (let i = 0; i < migrations.length; i++) existingDatabaseVersions.push(existingDatabaseVersions[existingDatabaseVersions.length - 1] + 1);\n\n\t\tlet currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion);\n\n\t\t// currentVersionIndex < 0 if for the case where an old version of Joplin used with a newer\n\t\t// version of the database, so that migration is not run in this case.\n\t\tif (currentVersionIndex < 0) {\n\t\t\tthrow new Error(\n\t\t\t\t'Unknown profile version. Most likely this is an old version of Joplin, while the profile was created by a newer version. Please upgrade Joplin at https://joplinapp.org and try again.\\n'\n\t\t\t\t+ `Joplin version: ${shim.appVersion()}\\n`\n\t\t\t\t+ `Profile version: ${fromVersion}\\n`\n\t\t\t\t+ `Expected version: ${existingDatabaseVersions[existingDatabaseVersions.length - 1]}`);\n\t\t}\n\n\t\tthis.logger().info(`Upgrading database from version ${fromVersion}`);\n\n\t\tif (currentVersionIndex === existingDatabaseVersions.length - 1) return fromVersion;\n\n\t\tlet latestVersion = fromVersion;\n\n\t\twhile (currentVersionIndex < existingDatabaseVersions.length - 1) {\n\t\t\tconst targetVersion = existingDatabaseVersions[currentVersionIndex + 1];\n\t\t\tthis.logger().info(`Converting database to version ${targetVersion}`);\n\n\t\t\tlet queries: (SqlQuery|string)[] = [];\n","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/laurent22/joplin/blob/2654b33620775080d1d59c552259d41e33dad3d2/packages/lib/JoplinDatabase.ts#L392-L428","documentation":"Thrown by JoplinDatabase migration logic when fromVersion (the profile's recorded schema version) is not in existingDatabaseVersions. existingDatabaseVersions is the base list [0..41] extended by each migration. An unknown fromVersion means the running Joplin is older than the one that created the profile; rather than silently corrupt data, Joplin refuses to start.","triggerScenarios":"User opens a profile created/last-opened by a NEWER Joplin build with an OLDER build — currentVersionIndex = existingDatabaseVersions.indexOf(fromVersion) returns -1.","commonSituations":"Downgrading Joplin after running a beta or a newer stable; copying a profile from a newer install to an older one; running an older AppImage against a synced profile.","solutions":["Upgrade Joplin to at least the version that created the profile (the error prints the expected version) — https://joplinapp.org.","If you must run the older version, use a separate fresh profile (`--profile /path/to/new`) so the newer profile is not corrupted.","Do not manually edit the profile version table — let Joplin migrate it."],"exampleFix":"# before: joplin --version 2.10 opens a profile last opened by 2.14\n# after: upgrade\nsudo snap refresh joplin   # or download the newer AppImage\njoplin","handlingStrategy":"try-catch","validationCode":"// Outside Joplin (tooling), detect a version mismatch before launch by reading the profile DB.\n// Inside Joplin there is no pre-check — the guard itself is the check.","typeGuard":"const isKnownProfileVersion = (v, known) => Number.isInteger(v) && known.includes(v);","tryCatchPattern":"try { await db.migrate(); }\ncatch (e) { if (/Unknown profile version/.test(e.message)) { /* prompt user to upgrade Joplin, do not attempt manual migration */ } else throw e; }","preventionTips":["Always upgrade Joplin; never downgrade against a newer profile.","If you need to test an older build, use a separate profile directory via --profile."],"tags":["database","migration","version-mismatch","startup"],"backgroundTag":null,"analyzedSha":"2654b33620775080d1d59c552259d41e33dad3d2","analyzedAt":"2026-08-12T14:26:46.263Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}