gastownhall/beads · error

remote URL cannot be empty

Error message

remote URL cannot be empty

What it means

ValidateRemoteURL() is the package's security boundary: every remote URL must pass it before being used in exec.Command arguments or SQL parameters. This error fires first when the URL string is empty — there is nothing to validate or clone from.

Source

Thrown at internal/remotecache/url.go:81

func IsRemoteURL(s string) bool {
	for _, scheme := range remoteSchemes {
		if strings.HasPrefix(s, scheme) {
			return true
		}
	}
	return gitSSHPattern.MatchString(s)
}

// ValidateRemoteURL performs strict security validation on a remote URL.
// It rejects URLs containing control characters (including null bytes),
// validates structural correctness per scheme, and rejects leading dashes
// that could be interpreted as CLI flags.
//
// This is a security boundary — all remote URLs should pass through this
// before reaching exec.Command arguments or SQL parameters.
func ValidateRemoteURL(rawURL string) error {
	if rawURL == "" {
		return fmt.Errorf("remote URL cannot be empty")
	}

	// Reject control characters (null bytes, newlines, tabs, etc.)
	for i, c := range rawURL {
		if c < 0x20 || c == 0x7f {
			return fmt.Errorf("remote URL contains control character at position %d (0x%02x)", i, c)
		}
	}

	// Reject leading dash (CLI flag injection via exec.Command arguments)
	if strings.HasPrefix(rawURL, "-") {
		return fmt.Errorf("remote URL must not start with a dash")
	}

	// SCP-style URLs (user@host:path) are validated separately
	if gitSSHPattern.MatchString(rawURL) {
		return validateSCPURL(rawURL)
	}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Set the remote URL before calling: e.g. dolthub://org/repo in bd config or the relevant env var.
  2. Check where the value originates (config file key present and non-empty, env var set) and fail fast with a clearer upstream message.
  3. Guard callers: skip cache operations entirely when no remote is configured instead of passing an empty string.
  4. Run `bd doctor`/config inspection to confirm the remote is configured.

Example fix

// before: calling with possibly-empty config value
_, err := cache.Ensure(ctx, cfg.RemoteURL)
// after: fail early with a clear message
if cfg.RemoteURL == "" {
    return fmt.Errorf("no remote configured: set remote_url in .beads/beads.json")
}
_, err := cache.Ensure(ctx, cfg.RemoteURL)
Defensive patterns

Strategy: validation

Validate before calling

func validateBeforeUse(remoteURL string) error {
    if strings.TrimSpace(remoteURL) == "" {
        return fmt.Errorf("remote URL is not configured")
    }
    return remotecache.ValidateRemoteURL(remoteURL)
}

Try / catch

if err := validateBeforeUse(cfg.RemoteURL); err != nil {
    return fmt.Errorf("check .beads/beads.json remote_url: %w", err)
}
return cache.Ensure(ctx, cfg.RemoteURL)

Prevention

When it happens

Trigger: Cache.Ensure(ctx, "") or ValidateRemoteURL("") / ValidateRemoteURLWithPatterns("", ...) with an unset remote URL — typically a missing config value, empty env var, or a function receiving an uninitialized variable.

Common situations: bd config file missing the remote/peer URL field; environment variable (e.g. for the remote) empty in CI; a code path building the URL from parts where the variable part resolved to empty; deserialized config with a blank value.

Related errors


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