{"record":{"id":"474347f756651d80","repo":"golang-migrate/migrate","slug":"invalid-repo","errorCode":null,"errorMessage":"invalid repo","messagePattern":"invalid repo","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"source/bitbucket/bitbucket.go","lineNumber":23,"sourceCode":"\t\"io\"\n\tnurl \"net/url\"\n\t\"os\"\n\t\"path\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/golang-migrate/migrate/v4/source\"\n\t\"github.com/ktrysmt/go-bitbucket\"\n)\n\nfunc init() {\n\tsource.Register(\"bitbucket\", &Bitbucket{})\n}\n\nvar (\n\tErrNoUserInfo             = fmt.Errorf(\"no username:password provided\")\n\tErrNoAccessToken          = fmt.Errorf(\"no password/app password\")\n\tErrInvalidRepo            = fmt.Errorf(\"invalid repo\")\n\tErrInvalidBitbucketClient = fmt.Errorf(\"expected *bitbucket.Client\")\n\tErrNoDir                  = fmt.Errorf(\"no directory\")\n)\n\ntype Bitbucket struct {\n\tconfig     *Config\n\tclient     *bitbucket.Client\n\tmigrations *source.Migrations\n}\n\ntype Config struct {\n\tOwner string\n\tRepo  string\n\tPath  string\n\tRef   string\n}\n\nfunc (b *Bitbucket) Open(url string) (source.Driver, error) {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/golang-migrate/migrate/blob/01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a/source/bitbucket/bitbucket.go#L5-L41","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Format the URL as `bitbucket://user:pass@owner/repo/path#ref` — owner is the host, repo is the first path segment.","Add the missing repo segment to the URL in your config.","Check the interpolated value of the repo variable before building the URL.","Validate the URL with net/url.Parse and assert a non-empty first path segment before calling migrate."],"exampleFix":"// before\nbitbucket://user:pass@myteam\n// after\nbitbucket://user:pass@myteam/myrepo/migrations#master","handlingStrategy":"validation","validationCode":"u, _ := nurl.Parse(sourceURL)\npe := strings.Split(strings.Trim(u.Path, \"/\"), \"/\")\nif u.Scheme == \"bitbucket\" && (u.Path == \"\" || pe[0] == \"\") {\n    return fmt.Errorf(\"bitbucket source URL needs /repo as first path segment\")\n}","typeGuard":"func hasRepoSegment(u *nurl.URL) bool {\n    pe := strings.Split(strings.Trim(u.Path, \"/\"), \"/\")\n    return len(pe) >= 1 && pe[0] != \"\"\n}","tryCatchPattern":"d, err := bitbucket.Open(url)\nif errors.Is(err, bitbucket.ErrInvalidRepo) {\n    return fmt.Errorf(\"invalid bitbucket source URL: use bitbucket://user:pass@owner/repo/path#ref\")\n}","preventionTips":["Remember the URL layout: host = owner, first path segment = repo.","Validate the composed URL with url.Parse before use.","Fail fast on empty repo placeholders in config templates.","Document the source URL format for your team."],"tags":["bitbucket","url","config","repo"],"backgroundTag":"invalid-source-url","analyzedSha":"01a9643f1475e75bb6d6224ddeaf9d8e2434ca8a","analyzedAt":"2026-09-02T19:38:29.671Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}