hashicorp/terraform · error

error parsing Git SSH URL: %s

Error message

error parsing Git SSH URL: %s

What it means

Raised in detectSSH (internal/getmodules/moduleaddrs/detect_git.go:131) when normalizing an SCP-like SSH module source (e.g. git@github.com:org/repo.git?depth=1). After the colon-delimited path is split on '?', the query portion is parsed with url.ParseQuery; if that fails (typically invalid percent-encoding such as %zz), this error propagates up through detectGit. The first return value of detectGit is also flagged true so callers treat it as a hard error rather than 'not recognized'.

Source

Thrown at internal/getmodules/moduleaddrs/detect_git.go:131

	}

	user := matched[1]
	host := matched[2]
	path := matched[3]
	qidx := strings.Index(path, "?")
	if qidx == -1 {
		qidx = len(path)
	}

	var u url.URL
	u.Scheme = "ssh"
	u.User = url.User(user)
	u.Host = host
	u.Path = path[0:qidx]
	if qidx < len(path) {
		q, err := url.ParseQuery(path[qidx+1:])
		if err != nil {
			return nil, fmt.Errorf("error parsing Git SSH URL: %s", err)
		}
		u.RawQuery = q.Encode()
	}

	return &u, nil
}

View on GitHub (pinned to c9def3e214)

Solutions

  1. Inspect the '?' portion of the SSH source string and fix or remove any invalid percent-encoded sequences (e.g. replace %zz with %25zz or drop the bad param).
  2. Percent-encode any literal '%' in query parameters as %25 before embedding them in the module source.
  3. Switch from SCP shorthand to a full ssh:// URL (ssh://git@example.com/org/repo.git?depth=1), which is parsed more leniently and avoids the SCP-path query extraction.
  4. Drop unnecessary query parameters and rely on go-getter defaults.

Example fix

// before
module "x" { source = "git@github.com:org/repo.git?depth=%zz" }
// after
module "x" { source = "git@github.com:org/repo.git?depth=1" }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the query string of an SCP-style SSH source before detection.
func validSSHQuery(src string) error {
	q := src
	if i := strings.Index(src, "?"); i != -1 {
		q = src[i+1:]
		if i2 := strings.Index(q, "#"); i2 != -1 {
			q = q[:i2]
		}
	}
	if q == "" {
		return nil
	}
	if _, err := url.ParseQuery(q); err != nil {
		return fmt.Errorf("invalid SSH query string %q: %w", q, err)
	}
	return nil
}

Try / catch

// detectGit-style errors surface as a normal Go error; branch on it.
result, ok, err := detectGit(src)
if err != nil {
    // src matched the SSH pattern but its query was malformed;
    // fix/encode the source and retry, do not silently ignore.
    return fmt.Errorf("module source %q is not a valid SSH URL: %w", src, err)
}

Prevention

When it happens

Trigger: A module source string matching the SSH pattern (user@host:path) whose query string after '?' contains an invalid percent-escape or malformed key=value pair, e.g. git@example.com:org/repo.git?ref=%zz or git@host:repo?foo===bar. url.ParseQuery rejects bad escapes and bad syntax.

Common situations: A developer copies a git clone URL with query args (depth, ref, sshkey) and accidentally includes a literal '%' that is not a valid hex escape; CI templating that injects unescaped tokens into the query string; Windows users pasting URLs with stray characters.

Related errors


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