theonedev/onedev · error · ExplicitException
Readonly file has been changed during upgrade:
Error message
Readonly file has been changed during upgrade:
What it means
During restoreProgramFiles in the upgrade handler, files marked read-only in the new program files are copied over existing ones only if the existing file is writable OR byte-identical. If a read-only destination file differs from the source, OneDev assumes local modifications and refuses to overwrite it, throwing this ExplicitException naming the file.
Source
Thrown at server-core/src/main/java/io/onedev/server/commandhandler/Upgrade.java:605
else
FileUtils.deleteDir(destChildFile);
}
}
} else {
if (destFile.isFile())
FileUtils.deleteFile(destFile);
FileUtils.createDir(destFile);
}
for (var srcChildFile: srcFile.listFiles())
restoreProgramFiles(srcChildFile, new File(destFile, srcChildFile.getName()));
} else try {
if (destFile.isDirectory())
FileUtils.deleteDir(destFile);
if (destFile.exists()) {
if (destFile.canWrite())
FileUtils.copyFile(srcFile, destFile);
else if (!Arrays.equals(FileUtils.readFileToByteArray(srcFile), FileUtils.readFileToByteArray(destFile)))
throw new ExplicitException("Readonly file has been changed during upgrade: " + destFile.getAbsolutePath());
} else {
FileUtils.copyFile(srcFile, destFile);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
protected void updateProgramFiles(File upgradeDir, int oldAppDataVersion) {
cleanAndCopy(new File(Bootstrap.installDir, "3rdparty-licenses"), new File(upgradeDir, "3rdparty-licenses"));
File siteServerScriptFile = new File(upgradeDir, "bin/server.sh");
for (File file: Bootstrap.getBinDir().listFiles()) {
if (!file.getName().endsWith(".pid") && !file.getName().endsWith(".status")) {
try {
String serverScript = null;
if (file.getName().equals("server.sh")) {
serverScript = FileUtils.readFileToString(file, Charset.defaultCharset());View on GitHub (pinned to d44925c47c)
Solutions
- Revert the named file to its original shipped content (or restore the whole previous program files from backup)
- Make the file writable so the upgrade can overwrite it: chmod u+w <file>
- Delete the changed file so the upgrade copies the fresh version in its place
- Re-run the upgrade command after fixing the file
Example fix
// before chmod 444 site/conf/system.properties && edit it // after chmod u+w site/conf/system.properties && revert edits, then run upgrade
Defensive patterns
Strategy: validation
Validate before calling
// compare readonly files before upgrading if (file.canWrite() == false && !Arrays.equals(readAll(src), readAll(dest))) revertFile(dest);
Try / catch
try { upgrade(); } catch (ExplicitException e) { if (e.getMessage().startsWith("Readonly file has been changed")) restoreOriginalFile(extractPath(e.getMessage())); } Prevention
- Never edit files in the OneDev site/program directories that ship read-only
- Keep site customizations outside shipped program files
- Snapshot the installation directory before upgrading
- Diff your installation against a clean copy before upgrading
When it happens
Trigger: Running an upgrade where the new version ships a read-only file (e.g. license, config template) whose content differs from the read-only file present in the current installation directory.
Common situations: Admins manually editing supposedly read-only files in the OneDev site directory, partial manual patches, or filesystem sync tools changing file contents between upgrades.
Related errors
- Unable to upgrade specified installation as database is not
- Unable to upgrade specified installation due to above error
- Unable to upgrade specified installation as data version of
- OneDev program is too old, please use a newer version
- OneDev is unable to restore old database, please do it manua
AI-assisted analysis of theonedev/onedev@d44925c47c (2026-09-06).
Data as JSON: /api/errors/25c2d06d218557d3.
Report an issue: GitHub.