From 96e8241a55b8e5a6565731dfa0b6781b20d68196 Mon Sep 17 00:00:00 2001 From: Alec Fong Date: Wed, 24 Jun 2026 10:06:08 -0700 Subject: [PATCH 1/2] fix: friendly error when registering a node with a duplicate name Intercept the dev-plane unique-constraint violation (externalnode_organization_id_name) and surface 'a node with this name already exists' instead of the raw pq error. This is a client-side string match as a stopgap; dev-plane should return a connect.CodeAlreadyExists error so we can match on the code instead. --- pkg/cmd/register/register.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkg/cmd/register/register.go b/pkg/cmd/register/register.go index e4c8367b..db138668 100644 --- a/pkg/cmd/register/register.go +++ b/pkg/cmd/register/register.go @@ -292,6 +292,12 @@ func runRegisterSteps(ctx context.Context, t *terminal.Terminal, s RegisterStore NodeSpec: toProtoNodeSpec(hwProfile), })) if err != nil { + // TODO: dev-plane should return a connect.CodeAlreadyExists error for a + // duplicate node name so we can match on the code instead of this brittle + // string match, which breaks if the constraint is ever renamed. + if strings.Contains(err.Error(), "externalnode_organization_id_name") { + return nil, fmt.Errorf("a node with this name already exists") + } return nil, fmt.Errorf("failed to register node: %w", err) } From eacfad03b43a2efcf1412fe120b279c5e61310ea Mon Sep 17 00:00:00 2001 From: Alec Fong Date: Wed, 24 Jun 2026 10:13:26 -0700 Subject: [PATCH 2/2] fix: also match connect AlreadyExists code for duplicate node name Forward-compatible with the dev-plane change that returns connect.CodeAlreadyExists; keep the constraint-name string match for older servers until the change is rolled out. --- pkg/cmd/register/register.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/cmd/register/register.go b/pkg/cmd/register/register.go index db138668..0f17d6a9 100644 --- a/pkg/cmd/register/register.go +++ b/pkg/cmd/register/register.go @@ -292,10 +292,12 @@ func runRegisterSteps(ctx context.Context, t *terminal.Terminal, s RegisterStore NodeSpec: toProtoNodeSpec(hwProfile), })) if err != nil { - // TODO: dev-plane should return a connect.CodeAlreadyExists error for a - // duplicate node name so we can match on the code instead of this brittle - // string match, which breaks if the constraint is ever renamed. - if strings.Contains(err.Error(), "externalnode_organization_id_name") { + // Newer dev-plane returns CodeAlreadyExists for a duplicate node name. + // Older dev-plane leaks the raw Postgres unique-constraint error, so we + // also match the constraint name for backwards compatibility until the + // server change is fully rolled out. + if connect.CodeOf(err) == connect.CodeAlreadyExists || + strings.Contains(err.Error(), "externalnode_organization_id_name") { return nil, fmt.Errorf("a node with this name already exists") } return nil, fmt.Errorf("failed to register node: %w", err)