opentofu/opentofu · error

connection type '%s' not supported

Error message

connection type '%s' not supported

What it means

Returned by communicator.New for any connection type other than "ssh", "" (empty, meaning the SSH default), or "winrm" (which gets its own removal-specific error). The string in the message is whatever the connection block's 'type' attribute evaluated to.

Source

Thrown at internal/communicator/communicator.go:76

	}

	typeVal := v.GetAttr("type")
	connType := ""
	if !typeVal.IsNull() {
		connType = typeVal.AsString()
	}

	switch connType {
	case "ssh", "": // The default connection type is ssh, so if connType is empty use ssh
		return ssh.New(v)
	case "winrm":
		// This connection type was valid in OpenTofu v1.12 and earlier, so
		// for now we'll keep a specalized error message for it as an aid to
		// anyone who tries to use a module that was written for an older
		// version.
		return nil, fmt.Errorf("'winrm' connections are not supported in OpenTofu v1.13 or later")
	default:
		return nil, fmt.Errorf("connection type '%s' not supported", connType)
	}
}

// maxBackoffDelay is the maximum delay between retry attempts
var maxBackoffDelay = 20 * time.Second
var initialBackoffDelay = time.Second

// in practice we want to abort the retry asap, but for tests we need to
// synchronize the return.
var retryTestWg *sync.WaitGroup

// Fatal is an interface that error values can return to halt Retry
type Fatal interface {
	FatalError() error
}

// Retry retries the function f until it returns a nil error, a Fatal error, or
// the context expires.

View on GitHub (pinned to 3561785c48)

Solutions

  1. Set type = "ssh" or remove the type attribute entirely (ssh is the default)
  2. Check spelling and case of the type value; run 'tofu validate' to catch it before apply
  3. If the type comes from a variable, print/verify its value (tofu console or null_resource triggers)

Example fix

# before
connection {
  type = "SSH"
  host = var.host
}
# after
connection {
  type = "ssh"
  host = var.host
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Before apply, validate every connection block's type against supported values
var supportedConnTypes = map[string]bool{"": true, "ssh": true}

func connTypeOK(t string) bool { return supportedConnTypes[t] }

Type guard

// Narrowing guard over raw config values (cty) for the connection type attribute
func supportedConnType(v cty.Value) bool {
  if v.IsNull() || v.Type() != cty.String {
    return false
  }
  switch v.AsString() {
  case "", "ssh":
    return true // "winrm" gets its own dedicated removal error
  default:
    return false
  }
}

Try / catch

_, err := communicator.New(connVal)
if err != nil && strings.Contains(err.Error(), "connection type") && strings.Contains(err.Error(), "not supported") {
  // config-level mistake: fail with the offending type highlighted, do not retry
  return fmt.Errorf("unsupported connection type %q: use \"ssh\" or omit type", connType)
}

Prevention

When it happens

Trigger: A provisioner connection block with type set to a typo or unsupported value: "sshh", "SSH" (capitalized), "sftp", "rdp", or a variable that interpolates to something unexpected (including a null/unknown value passed as string "null").

Common situations: Typos in copied connection blocks; case sensitivity surprises ("SSH" is not accepted); using a type valid in other tools (e.g. Paramiko strings) that OpenTofu never supported; ternary expressions in type that yield a wrong branch.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/a7c1b3d1f477686c. Report an issue: GitHub.