gastownhall/beads · error

SCP-style URL must be in user@host:path format

Error message

SCP-style URL must be in user@host:path format

What it means

SCP-style remote URLs must look like user@host:path. This error guards validateSCPURL's invariants: it runs only after gitSSHPattern matched, so in practice the pattern already guarantees "@" and ":" are present and this branch is defensive/unreachable for normal input — but if reached, the string lacked an @ or a colon after it.

Source

Thrown at internal/remotecache/url.go:184

			return fmt.Errorf("oci:// URL must include a namespace or bucket host")
		}
	case "file":
		// file:// is allowed with any path
	case "git+file":
		// git+file:// is Dolt's normalized form for local git remotes.
	}

	return nil
}

// validateSCPURL validates an SCP-style URL (user@host:path)
func validateSCPURL(rawURL string) error {
	// Already matched gitSSHPattern, so structure is valid.
	// Extract host and verify no control chars (already checked above).
	atIdx := strings.Index(rawURL, "@")
	colonIdx := strings.Index(rawURL[atIdx:], ":")
	if atIdx < 0 || colonIdx < 0 {
		return fmt.Errorf("SCP-style URL must be in user@host:path format")
	}
	return nil
}

// ValidateRemoteName checks that a remote name is safe for use as a Dolt
// remote identifier. Names must start with a letter and contain only
// alphanumeric characters, hyphens, and underscores. Max 64 characters.
func ValidateRemoteName(name string) error {
	if name == "" {
		return fmt.Errorf("remote name cannot be empty")
	}
	if len(name) > 64 {
		return fmt.Errorf("remote name too long (max 64 characters)")
	}
	if strings.HasPrefix(name, "-") {
		return fmt.Errorf("remote name must not start with a dash")
	}
	if !validRemoteNameRegex.MatchString(name) {

View on GitHub (pinned to 71377f2769)

Solutions

  1. Use the full SCP form: "git@github.com:org/repo.git"
  2. If you prefer scheme syntax, use "ssh://git@github.com/org/repo.git" instead
  3. Remember the separator after the host is a colon, not a slash

Example fix

// before
remote := "git@github.com/org/repo"
// after
remote := "git@github.com:org/repo"
Defensive patterns

Strategy: validation

Validate before calling

var scpRe = regexp.MustCompile(`^[^@\s]+@[^@\s:]+:.+$`)
func validSCPForm(u string) bool { return scpRe.MatchString(u) }
// check before passing to ValidateRemoteURL

Type guard

func isSCPStyle(s string) bool {
	return regexp.MustCompile(`^[a-zA-Z0-9._-]+@[a-zA-Z0-9][a-zA-Z0-9._-]*:[^\x00-\x1f\x7f]+$`).MatchString(s)
}

Try / catch

if err := remotecache.ValidateRemoteURL(u); err != nil {
	if strings.Contains(err.Error(), "user@host:path") {
		return fmt.Errorf("remote %q must be git@host:path or ssh://host/path", u)
	}
}

Prevention

When it happens

Trigger: ValidateRemoteURL with an SCP-shaped string missing "@" or missing ":" after the host. Because gitSSHPattern requires both, this is only reachable if the pattern and this check diverge (e.g. future pattern changes).

Common situations: Typing a git remote without the colon separator ("git@example.com/path") or without the user part, expecting it to be accepted as SSH.

Related errors


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