hashicorp/terraform · error

Invalid TCP address %q for %q: %w

Error message

Invalid TCP address %q for %q: %w

What it means

ParseReattachProviders found Addr.Network="tcp" but net.ResolveTCPAddr could not parse Addr.String into host:port, so the plugin client would have no endpoint to dial. The entry is rejected and reattach aborts.

Source

Thrown at internal/getproviders/reattach/reattach.go:71

		if err != nil {
			return unmanagedProviders, fmt.Errorf("Invalid format for %s: %w", TF_REATTACH_PROVIDERS, err)
		}
		for p, c := range m {
			a, diags := addrs.ParseProviderSourceString(p)
			if diags.HasErrors() {
				return unmanagedProviders, fmt.Errorf("Error parsing %q as a provider address: %w", a, diags.Err())
			}
			var addr net.Addr
			switch c.Addr.Network {
			case "unix":
				addr, err = net.ResolveUnixAddr("unix", c.Addr.String)
				if err != nil {
					return unmanagedProviders, fmt.Errorf("Invalid unix socket path %q for %q: %w", c.Addr.String, p, err)
				}
			case "tcp":
				addr, err = net.ResolveTCPAddr("tcp", c.Addr.String)
				if err != nil {
					return unmanagedProviders, fmt.Errorf("Invalid TCP address %q for %q: %w", c.Addr.String, p, err)
				}
			default:
				return unmanagedProviders, fmt.Errorf("Unknown address type %q for %q", c.Addr.Network, p)
			}
			unmanagedProviders[a] = &plugin.ReattachConfig{
				Protocol:        plugin.Protocol(c.Protocol),
				ProtocolVersion: c.ProtocolVersion,
				Pid:             c.Pid,
				Test:            c.Test,
				Addr:            addr,
			}
		}
	}
	return unmanagedProviders, nil
}

// IsProviderReattached determines if a given provider is being supplied to Terraform via the TF_REATTACH_PROVIDERS
// environment variable.

View on GitHub (pinned to c9def3e214)

Solutions

  1. Set Addr.String to a full host:port pair, e.g. "127.0.0.1:12345".
  2. Ensure the provider process printed its listener address before Terraform reads TF_REATTACH_PROVIDERS (serialize/launch ordering).
  3. For IPv6 use bracketed form like "[::1]:12345".

Example fix

// before
"Addr": {"Network":"tcp","String":"localhost"}
// after
"Addr": {"Network":"tcp","String":"127.0.0.1:12345"}
Defensive patterns

Strategy: validation

Validate before calling

import "net"

// Validate a TCP reattach address before building the env var.
func validateTCPAddr(p, hostPort string) error {
    if _, err := net.ResolveTCPAddr("tcp", hostPort); err != nil {
        return fmt.Errorf("invalid tcp address %q for %q: %w", hostPort, p, err)
    }
    return nil
}

Prevention

When it happens

Trigger: TF_REATTACH_PROVIDERS entry with Addr.Network="tcp" and an Addr.String missing a port ("127.0.0.1"), with a non-numeric port ("localhost:x"), or otherwise malformed per Go's net.ResolveTCPAddr rules.

Common situations: Dynamic port assigned by the provider process not yet substituted into the JSON template; "localhost" used where an IP is needed in a sandbox without resolver; port field accidentally serialized as a number into the string; IPv6 address written without brackets.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/dba0c721d229620f. Report an issue: GitHub.