Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions docs/content/guides/troubleshooting.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,9 @@ Context holding ports as app-main, and resolving app now
## The daemon is serving an old build

A running daemon keeps serving the build it started as, and it only complains about a mismatch when the wire protocol changed. After upgrading grove, `grove restart`. Detached ports are taken again on the far side; a lease held by a running command is not, so that command has to be run again, and restart tells you which routes that cost.

## Two projects install different groves

One daemon serves the machine, so when the wire protocol changes between versions only one of those groves can talk to it. Whichever project restarts last owns the daemon, and every project on the other version gets a protocol mismatch until it upgrades too. Restarting from the stranded project only trades which one works.

The fix is to put every project on the same grove, not to keep restarting. [`grove doctor`](/reference/cli/doctor) reads the version a project installs under `Project grove`, which is where a workspace resolving more than one shows up.
2 changes: 1 addition & 1 deletion internal/daemon/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,5 @@ func (e *VersionError) Error() string {
// from inside a project that installed grove rather than from a shell that
// has it on PATH.
grove := shell.Invocation()
return fmt.Sprintf("the running daemon speaks control protocol v%d and this grove speaks v%d; restart it with '%s restart', then '%s hold' in each project, since a restart drops every detached port", e.Daemon, e.CLI, grove, grove)
return fmt.Sprintf("the running daemon speaks control protocol v%d and this grove speaks v%d; restart it with '%s restart' to hand it to this build, which says what that cost. One daemon serves the machine, so a project installing the other version cannot reach it until that project upgrades too.", e.Daemon, e.CLI, grove)
}
7 changes: 5 additions & 2 deletions internal/daemon/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,10 @@ func TestClientNamesAnOlderDaemon(t *testing.T) {
if !errors.As(err, &mismatch) {
t.Fatalf("err = %v, want VersionError", err)
}
for _, want := range []string{"grove restart", "grove hold"} {
// The prose as well as the command: a restart alone settles nothing while
// two projects install different versions, and that is the half worth
// keeping asserted.
for _, want := range []string{"grove restart", "One daemon serves the machine"} {
if !strings.Contains(err.Error(), want) {
t.Errorf("error does not name %q, so it says a problem without a way out: %v", want, err)
}
Expand Down Expand Up @@ -924,7 +927,7 @@ func TestTheErrorsNameHowGroveWasReached(t *testing.T) {
grove := shell.Invocation()

mismatch := (&daemon.VersionError{Daemon: 3, CLI: 4}).Error()
if !strings.Contains(mismatch, "'"+grove+" restart'") || !strings.Contains(mismatch, "'"+grove+" hold'") {
if !strings.Contains(mismatch, "'"+grove+" restart'") {
t.Errorf("version error does not name the caller's grove: %q", mismatch)
}

Expand Down
Loading