hashicorp/terraform · error

unsupported protocol version

Error message

unsupported protocol version %d

What it means

After an unmanaged provider client is created and connected, providerFactoriesFromLocks/finalizeFactoryPlugin switches on client.NegotiatedVersion(). Only 0, 5, and 6 are handled; any other negotiated protocol falls through to this error. Unlike 726 (which fires before connecting), this fires after a successful handshake but on a protocol the runtime cannot wrap.

Solutions

  1. Kill the old provider process referenced by TF_REATTACH_PROVIDERS and restart the one matching the current CLI build.
  2. Upgrade the Terraform/OpenTofu CLI to a version that supports the negotiated protocol, or downgrade the provider to proto 5/6.
  3. Clear TF_REATTACH_PROVIDERS from the environment when not actively debugging.
  4. Verify terraform-plugin-go / terraform-plugin-framework versions in the provider's go.mod match a supported protocol.

Example fix

# before: provider negotiates proto 7
# after: rebuild provider against framework v1.x (proto 6)
go get github.com/hashicorp/terraform-plugin-framework@latest
go build && rerun the provider harness
Defensive patterns

Strategy: validation

Validate before calling

// After connecting, gate on NegotiatedVersion before using the provider.
if v := client.NegotiatedVersion(); v != 0 && v != 5 && v != 6 {
    return fmt.Errorf("negotiated protocol %d unsupported by this build", v)
}

Prevention

When it happens

Trigger: TF_REATTACH_PROVIDERS points at a running provider server whose gRPC handshake negotiated a protocol version other than 5 or 6 (e.g. a future protocol 7, or a misreported value). NegotiatedVersion() returns that value after client.Client()/Dispense succeed.

Common situations: Provider built against a newer terraform-plugin-go than the CLI supports; provider built against an experimental protocol; stale running provider process from an older dev session still bound to the reattach socket.

Related errors


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

Appendix: source

Thrown at internal/command/meta_providers.go:580

		raw, err := rpcClient.Dispense(tfplugin.ProviderPluginName)
		if err != nil {
			return nil, err
		}

		// store the client so that the plugin can kill the child process
		protoVer := client.NegotiatedVersion()
		switch protoVer {
		case 0, 5:
			// As of the 0.15 release, sdk.v2 doesn't include the protocol
			// version in the ReattachConfig (only recently added to
			// go-plugin), so client.NegotiatedVersion() always returns 0. We
			// assume that an unmanaged provider reporting protocol version 0 is
			// actually using proto v5 for backwards compatibility.
			return finalizeFactoryPlugin(raw, 5, provider, client), nil
		case 6:
			return finalizeFactoryPlugin(raw, 6, provider, client), nil
		default:
			return nil, fmt.Errorf("unsupported protocol version %d", protoVer)
		}
	}
}

// providerFactoryError is a stub providers.Factory that returns an error
// when called. It's used to allow providerFactories to still produce a
// factory for each available provider in an error case, for situations
// where the caller can do something useful with that partial result.
func providerFactoryError(err error) providers.Factory {
	return func() (providers.Interface, error) {
		return nil, err
	}
}

// providerPluginErrors is an error implementation we can return from
// Meta.providerFactories to capture potentially multiple errors about the
// locally-cached plugins (or lack thereof) for particular external providers.
//

View on GitHub (pinned to d32a084675)