diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index b37598483f..61e8a55393 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,6 +1,7 @@
#### Unreleased
* `paket pack --symbols` no longer fails on a project with Compile entries without an `Include` or `Update` attribute, such as `` or a Compile item definition in an `ItemDefinitionGroup`, and leaves out of the symbols package the files that a Remove names without wildcards - https://github.com/fsprojects/Paket/issues/4222
+* `paket update --no-install` no longer fails when a group has `generate_load_scripts: true` and the packages of the new paket.lock aren't all restored, as on a fresh checkout or for a package that the update adds: it leaves the load scripts to the next restore, which downloads the packages that they load - https://github.com/fsprojects/Paket/issues/2785
#### 12.0.0-alpha005 - 2026-11-07
diff --git a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs
index 455ca3fc61..29eb2fe250 100644
--- a/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs
+++ b/integrationtests/Paket.IntegrationTests/LoadingScriptGenerationTests.fs
@@ -268,6 +268,24 @@ let ``#3238 restore regenerates load scripts when .paket/load folder is missing`
nHibernate35Expectations |> assertExpectations scenario ExpectationType.ShouldContain
+[]
+let ``#2785 update --no-install leaves the load scripts to the restore`` () =
+ // generate_load_scripts: true, and nothing restored yet
+ let scenario = "issue-2939"
+ let cleanup, output = paket "update --no-install" scenario
+ use __ = cleanup
+ StringAssert.Contains("The load scripts will be generated by the next paket restore", output)
+
+ let tempPath = scenarioTempPath scenario
+ Assert.IsTrue(File.Exists(Path.Combine(tempPath, "paket.lock")), "update should write paket.lock")
+ Assert.IsFalse(Directory.Exists(Path.Combine(tempPath, "packages", "Newtonsoft.Json")), "--no-install should not download the packages")
+ Assert.IsFalse((scriptRoot scenario).Exists, "--no-install should not generate the load scripts")
+
+ directPaket "restore" scenario |> ignore
+
+ let newtonsoftScript = Path.Combine((scriptRoot scenario).FullName, "Newtonsoft.Json.fsx")
+ Assert.IsTrue(File.Exists newtonsoftScript, "restore should generate the load scripts")
+
[]
let ``issue 2156 netstandard`` () =
let scenario = "issue-2156"
diff --git a/src/Paket.Core/Installation/UpdateProcess.fs b/src/Paket.Core/Installation/UpdateProcess.fs
index 0ca4518e1f..3d63f8df3d 100644
--- a/src/Paket.Core/Installation/UpdateProcess.fs
+++ b/src/Paket.Core/Installation/UpdateProcess.fs
@@ -297,7 +297,12 @@ let SmartInstall(dependenciesFile:DependenciesFile, updateMode, options : Update
|> Seq.tryHead
|> Option.isSome
- if shouldGenerateScripts then
+ // --no-install doesn't download the packages that the scripts load. When the lock file changes,
+ // the restore cache no longer matches it, so the next restore downloads them and generates the scripts (#2785)
+ if shouldGenerateScripts && options.NoInstall then
+ if hasChanged then
+ tracefn "The load scripts will be generated by the next paket restore, which downloads the packages."
+ elif shouldGenerateScripts then
let groupsToGenerate =
if options.Common.GenerateLoadScripts then [] else
dependenciesFile.Groups