# feat(git-remote-entire): surface wrong-cluster clone errors clearly

`97aa0c9`→[main](/content/gh/entireio/cli/commits/main/index.html)·

toothbrush·2w ago·3 files·+96 added/-6 removed

When a repo lives on a different cluster than the one in the entire://
URL, the data plane rejects the token exchange with an RFC 8693
invalid_target carrying an error_description naming the correct host.
Previously this surfaced as a raw, multiply-wrapped HTTP 400 JSON blob.

Now git-remote-entire detects this case and prints an actionable message
naming the correct host and the corrected `git clone entire://...` URL.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

## Sessions

7cf3c440ed71View transcript

## Changes

3

- cmd/git-remote-entire

- Mmain.go+32/-1

- Mmain_test.go+57

- internal/entireclient/httputil

- Moauth.go+7/-5

```go
import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"runtime"
	"strings"
	"syscall"
	"github.com/entireio/cli/cmd/entire/cli/versioninfo"
	"github.com/entireio/cli/internal/entireclient/clusterdiscovery"
	"github.com/entireio/cli/internal/entireclient/httpclient"
	"github.com/entireio/cli/internal/entireclient/httputil"
	"github.com/entireio/cli/internal/entireclient/repocreds"
	"github.com/entireio/cli/internal/entireclient/userdirs"
	"github.com/entireio/cli/internal/remotehelper"
)
```

// wrongClusterRe extracts the host that actually serves the repo from the
// data plane's `invalid_target` error_description (RFC 8693). The data plane
// emits this when the audience host doesn't host the repo but a sibling
// cluster does, naming the correct host so we can point the user at it. The
// phrasing is "… it lives on \"<host>\" …"; anchoring on "lives on" keeps the
// match tied to this specific, actionable case rather than other
// invalid_target variants (e.g. a suspended mirror).
var wrongClusterRe = regexp.MustCompile(`lives on "([^"]+)"`)

// fatalMessage renders the stderr "fatal: …" line for a transfer error. When
// the failure is the data plane reporting that the repo lives on a different
// cluster, it special-cases the raw OAuth chain into an actionable message
// naming the correct host (and the corrected entire:// URL). Everything else
// falls back to the verbatim error.
func fatalMessage(err error, parsedURL *url.URL) string {
	var oe *httputil.OAuthError
	if errors.As(err, &oe) && oe.Code == "invalid_target" {
		if m := wrongClusterRe.FindStringSubmatch(oe.Description); m != nil {
			host := m[1]
			corrected := (&url.URL{Scheme: "entire", Host: host, Path: parsedURL.Path}).String()
			return fmt.Sprintf("fatal: this repository is not hosted on %s; it lives on %s.\nRe-run against the correct host, e.g.:\n\n    git clone %s\n", parsedURL.Host, host, corrected)
		}
	}
	return fmt.Sprintf("fatal: %v\n", err)
}

// loadedVersion populates the build info and returns the resolved version.
func loadedVersion() string {
	versioninfo.Load()
}

func TestFatalMessage(t *testing.T) {
	t.Parallel()
	parsedURL := &url.URL{Scheme: "entire", Host: "aws-us-east-2.entire.io", Path: "/et/paul/dogbark"}
	wrongCluster := &httputil.OAuthError{
		Status:      http.StatusBadRequest,
		Code:        "invalid_target",
		Description: `audience host "aws-us-east-2.entire.io" does not host this repo; it lives on "aws-eu-central-1.entire.io" — re-target the request there`,
		Body:        "{...}",
	}
	tests := []struct {
		name        string
		err         error
		contains    []string
		notContains []string
	}{
		{
			name: "wrong cluster names correct host and URL",
			// Wrapped to mirror production: the OAuthError surfaces buried under
			// several fmt.Errorf layers, so errors.As must dig it out.
			err: fmt.Errorf("stateless-connect v2 info/refs: fetching info/refs from entry domain: repo-scoped token exchange: oauth token exchange: %w", wrongCluster),
			contains: []string{
				"aws-eu-central-1.entire.io",
				"git clone entire://aws-eu-central-1.entire.io/et/paul/dogbark",
			},
			notContains: []string{"HTTP 400", "invalid_target"},
		},
		{
			name:     "invalid_target without lives-on hint falls back",
			err:      &httputil.OAuthError{Status: http.StatusBadRequest, Code: "invalid_target", Description: "no servable mirror", Body: "HTTP 400: no servable mirror"},
			contains: []string{"fatal:", "no servable mirror"},
		},
		{
			name:     "unrelated error falls back verbatim",
			err:      errors.New("connection refused"),
			contains: []string{"fatal: connection refused"},
		},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			t.Parallel()
			got := fatalMessage(tc.err, parsedURL)
			for _, sub := range tc.contains {
				if !strings.Contains(got, sub) {
					t.Errorf("fatalMessage() = %q, missing %q", got, sub)
				}
			}
			for _, sub := range tc.notContains {
				if strings.Contains(got, sub) {
					t.Errorf("fatalMessage() = %q, should not contain %q", got, sub)
				}
			}
		}
	}
}
