gastownhall/beads · error

remote URL is malformed: %w

Error message

remote URL is malformed: %w

What it means

The scheme passed the allowlist but net/url could not parse the (normalized) URL. The underlying url.Parse error is wrapped, so errors.Is/As against *url.Error works. For git+* schemes the library rewrites the scheme to "placeholder" before parsing to work around net/url limitations.

Source

Thrown at internal/remotecache/url.go:129

		scheme = rawURL[:idx]
		// For net/url parsing, replace git+ssh with a parseable scheme
		if strings.HasPrefix(scheme, "git+") {
			normalizedURL = rawURL[len(scheme)+3:] // strip scheme://
			normalizedURL = "placeholder://" + normalizedURL
		}
	}

	if scheme == "" {
		return fmt.Errorf("remote URL has no scheme (expected one of: %s)", strings.Join(sortedSchemes(), ", "))
	}

	if !allowedSchemes[scheme] {
		return fmt.Errorf("remote URL scheme %q is not allowed (expected one of: %s)", scheme, strings.Join(sortedSchemes(), ", "))
	}

	parsed, err := url.Parse(normalizedURL)
	if err != nil {
		return fmt.Errorf("remote URL is malformed: %w", err)
	}

	// Scheme-specific structural validation
	switch scheme {
	case "dolthub":
		// dolthub://org/repo — requires org and repo
		p := strings.TrimPrefix(parsed.Path, "/")
		host := parsed.Host
		combined := host
		if p != "" {
			combined = host + "/" + p
		}
		parts := strings.Split(combined, "/")
		if len(parts) < 2 || parts[0] == "" || parts[1] == "" {
			return fmt.Errorf("dolthub:// URL must have org/repo format (e.g., dolthub://myorg/myrepo)")
		}
	case "https", "http", "git+https", "git+http":
		if parsed.Host == "" {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Fix the URL syntax per the wrapped *url.Error message (bad host, invalid port, invalid escape)
  2. Percent-encode special characters in path/query portions (e.g. spaces as %20)
  3. Quote the URL in shell/config so interpolation doesn't corrupt it

Example fix

// before
remote := "https://my host.example.com/repo"
// after
remote := "https://my-host.example.com/repo"
Defensive patterns

Strategy: validation

Validate before calling

func parseableURL(u string) error {
	_, err := url.Parse(u)
	return err
}
if err := parseableURL(remote); err != nil {
	return fmt.Errorf("bad remote URL %q: %w", remote, err)
}

Type guard

func isParseableURL(s string) bool {
	_, err := url.Parse(s)
	return err == nil
}

Try / catch

if err := remotecache.ValidateRemoteURL(u); err != nil {
	var urlErr *url.Error
	if errors.As(err, &urlErr) {
		return fmt.Errorf("malformed remote URL %q: %v", u, urlErr.Err)
	}
}

Prevention

When it happens

Trigger: ValidateRemoteURL with a structurally invalid URL for an allowed scheme, e.g. "https://[bad::ipv6", "http://exa mple.com", or a URL with invalid percent-encoding like "https://h/%zz".

Common situations: Copy-paste errors introducing stray spaces or brackets, shell expansions mangling the URL, or hand-assembled URLs with unescaped/invalid characters.

Understand the failure class

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/764f5fb6767e1b76. Report an issue: GitHub.