hashicorp/terraform · error

Invalid URL: %v must be: %v

Error message

Invalid URL: %v must be: %v

What it means

Raised in Backend.configure() (cos/backend.go:309) when the `endpoint` attribute is set but does not match the strict regex ^(http(s)?)://cos-internal\.([^.]+)\.tencentcos\.cn$. The endpoint option only accepts the COS internal-access form; any other URL shape is rejected.

Source

Thrown at internal/backend/remote-state/cos/backend.go:309

		u, err = url.Parse(fmt.Sprintf("https://%s.cos.%s.myqcloud.com", b.bucket, b.region))
	}
	if err != nil {
		return err
	}

	if v, ok := data.GetOk("domain"); ok {
		b.domain = v.(string)
		log.Printf("[DEBUG] Backend: set domain for TencentCloud API client. Domain: [%s]", b.domain)
	}
	// set url as endpoint when provided
	// "http://{Bucket}.cos-internal.{Region}.tencentcos.cn"
	if v, ok := data.GetOk("endpoint"); ok {
		endpoint := v.(string)

		re := regexp.MustCompile(`^(http(s)?)://cos-internal\.([^.]+)\.tencentcos\.cn$`)
		matches := re.FindStringSubmatch(endpoint)
		if len(matches) != 4 {
			return fmt.Errorf("Invalid URL: %v must be: %v", endpoint, "http(s)://cos-internal.{Region}.tencentcos.cn")
		}

		protocol := matches[1]
		region := matches[3]

		// URL after converting
		newUrl := fmt.Sprintf("%s://%s.cos-internal.%s.tencentcos.cn", protocol, b.bucket, region)
		u, err = url.Parse(newUrl)
		log.Printf("[DEBUG] Backend: set COS URL as: [%s]", newUrl)
	}
	if err != nil {
		return err
	}

	var getProviderConfig = func(key string) string {
		var str string
		value, err := getConfigFromProfile(data, key)
		if err == nil && value != nil {

View on GitHub (pinned to c9def3e214)

Solutions

  1. Use the exact form endpoint = "https://cos-internal.ap-guangzhou.tencentcos.cn" with a real region.
  2. If you want the public endpoint, omit the endpoint attribute entirely; the backend builds the public URL from region/bucket.
  3. Verify the region segment matches a valid TencentCloud region.

Example fix

// before
terraform {
  backend "cos" {
    region   = "ap-guangzhou"
    bucket   = "my-bucket"
    endpoint = "https://cos.ap-guangzhou.myqcloud.com"
  }
}
// after
terraform {
  backend "cos" {
    region   = "ap-guangzhou"
    bucket   = "my-bucket"
    endpoint = "https://cos-internal.ap-guangzhou.tencentcos.cn"
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the cos endpoint matches the internal-access form
var endpointRe = regexp.MustCompile(`^(http(s)?)://cos-internal\.([^.]+)\.tencentcos\.cn$`)
func validEndpoint(ep string) error {
    if len(endpointRe.FindStringSubmatch(ep)) != 4 {
        return fmt.Errorf("Invalid URL: %v must be: %v", ep, "http(s)://cos-internal.{Region}.tencentcos.cn")
    }
    return nil
}

Prevention

When it happens

Trigger: Configuring endpoint = "https://cos.ap-guangzhou.myqcloud.com" or any string that does not exactly match http(s)://cos-internal.<region>.tencentcos.cn; the regex match returns fewer than 4 groups.

Common situations: Trying to use the public COS endpoint via the endpoint option (not supported - endpoint is internal-only); typos in the domain; wrong region segment; missing protocol.

Related errors


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