golang-migrate/migrate · error

no directory

Error message

no directory

What it means

github.ErrNoDir is returned by Github.readDirectory when the GitHub Contents API returns a single file instead of directory contents, meaning the configured path points at a file, not a directory of migrations.

Source

Thrown at source/github/github.go:28

	"path"
	"strings"

	"golang.org/x/oauth2"

	"github.com/golang-migrate/migrate/v4/source"
	"github.com/google/go-github/v39/github"
)

func init() {
	source.Register("github", &Github{})
}

var (
	ErrNoUserInfo          = fmt.Errorf("no username:token provided")
	ErrNoAccessToken       = fmt.Errorf("no access token")
	ErrInvalidRepo         = fmt.Errorf("invalid repo")
	ErrInvalidGithubClient = fmt.Errorf("expected *github.Client")
	ErrNoDir               = fmt.Errorf("no directory")
)

type Github struct {
	config     *Config
	client     *github.Client
	options    *github.RepositoryContentGetOptions
	migrations *source.Migrations
}

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

func (g *Github) Open(url string) (source.Driver, error) {
	u, err := nurl.Parse(url)

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Point the path at the migrations directory, not an individual file (path without a filename)
  2. Verify the directory exists on the configured Ref (branch/tag/sha) via the GitHub UI or API
  3. If the repo keeps migrations at root or a subdir, adjust the URL path segment after owner/repo

Example fix

// before
source.Open("github://user:token@github.com/owner/repo/migrations/0001_init.up.sql")
// after
source.Open("github://user:token@github.com/owner/repo/migrations")
Defensive patterns

Strategy: validation

Validate before calling

// before opening, confirm the path is a directory on the ref:
_, dir, _, err := client.Repositories.GetContents(ctx, owner, repo, path, &github.RepositoryContentGetOptions{Ref: ref})
if err != nil {
    return err
}
if dir == nil {
    return fmt.Errorf("%s on ref %s is a file, not a directory", path, ref)
}

Type guard

func isDirectoryContent(fc *github.RepositoryContent, dir []*github.RepositoryContent) bool {
    return fc == nil && len(dir) > 0
}

Try / catch

d, err := source.Open(srcURL)
if err != nil {
    if errors.Is(err, source_github.ErrNoDir) {
        return fmt.Errorf("path in %q points to a file; use the migrations directory", srcURL)
    }
    return err
}

Prevention

When it happens

Trigger: Configuring Path (or the URL path) to a single file such as .../migrations/0001_init.sql; the API returns fileContent != nil and readDirectory returns ErrNoDir.

Common situations: Typos in the migrations path; pointing at a symlink or a path that was moved; confusing file URL vs directory URL when copying from a GitHub blob URL.

Related errors


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