golang-migrate/migrate · error

invalid repo

Error message

invalid repo

What it means

ErrInvalidRepo is returned by Open when the URL path yields no repo segment after trimming slashes. The driver splits u.Path on '/' and requires at least one element to use as the repo slug. In practice a URL with no path (e.g. `bitbucket://user:pass@owner`) triggers it. Exported sentinel error.

Source

Thrown at source/bitbucket/bitbucket.go:23

	"io"
	nurl "net/url"
	"os"
	"path"
	"path/filepath"
	"strings"

	"github.com/golang-migrate/migrate/v4/source"
	"github.com/ktrysmt/go-bitbucket"
)

func init() {
	source.Register("bitbucket", &Bitbucket{})
}

var (
	ErrNoUserInfo             = fmt.Errorf("no username:password provided")
	ErrNoAccessToken          = fmt.Errorf("no password/app password")
	ErrInvalidRepo            = fmt.Errorf("invalid repo")
	ErrInvalidBitbucketClient = fmt.Errorf("expected *bitbucket.Client")
	ErrNoDir                  = fmt.Errorf("no directory")
)

type Bitbucket struct {
	config     *Config
	client     *bitbucket.Client
	migrations *source.Migrations
}

type Config struct {
	Owner string
	Repo  string
	Path  string
	Ref   string
}

func (b *Bitbucket) Open(url string) (source.Driver, error) {

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Format the URL as `bitbucket://user:pass@owner/repo/path#ref` — owner is the host, repo is the first path segment.
  2. Add the missing repo segment to the URL in your config.
  3. Check the interpolated value of the repo variable before building the URL.
  4. Validate the URL with net/url.Parse and assert a non-empty first path segment before calling migrate.

Example fix

// before
bitbucket://user:pass@myteam
// after
bitbucket://user:pass@myteam/myrepo/migrations#master
Defensive patterns

Strategy: validation

Validate before calling

u, _ := nurl.Parse(sourceURL)
pe := strings.Split(strings.Trim(u.Path, "/"), "/")
if u.Scheme == "bitbucket" && (u.Path == "" || pe[0] == "") {
    return fmt.Errorf("bitbucket source URL needs /repo as first path segment")
}

Type guard

func hasRepoSegment(u *nurl.URL) bool {
    pe := strings.Split(strings.Trim(u.Path, "/"), "/")
    return len(pe) >= 1 && pe[0] != ""
}

Try / catch

d, err := bitbucket.Open(url)
if errors.Is(err, bitbucket.ErrInvalidRepo) {
    return fmt.Errorf("invalid bitbucket source URL: use bitbucket://user:pass@owner/repo/path#ref")
}

Prevention

When it happens

Trigger: `bitbucket://user:pass@owner` or `bitbucket://user:pass@owner/` with an empty path — len(pe) < 1 after Trim/ Split. Note: a completely empty path also yields pe == [""] with len 1, so this fires only for pathless-but-nonempty split outcomes; a truly empty repo still results in downstream API errors, so always supply /repo.

Common situations: Copy-pasting a database-style URL and dropping the repo segment; template/config where the repo placeholder stayed empty; confusion between owner (host) and repo (first path segment) layout of the bitbucket URL scheme.

Related errors


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/474347f756651d80. Report an issue: GitHub.