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
- Kill the old provider process referenced by TF_REATTACH_PROVIDERS and restart the one matching the current CLI build.
- Upgrade the Terraform/OpenTofu CLI to a version that supports the negotiated protocol, or downgrade the provider to proto 5/6.
- Clear TF_REATTACH_PROVIDERS from the environment when not actively debugging.
- 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
- Match CLI and provider protocol generations (use proto 6 framework providers with modern Terraform).
- Kill stale provider processes from previous dev sessions before reattaching.
- Avoid TF_REATTACH_PROVIDERS outside development.
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
- no supported plugins for protocol
- error when obtaining provider instance during state store…
- action schema not found for action
- error loading plugin path
- error loading plugin path
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)