golang-migrate/migrate · error
malformed migration filename: %s
Error message
malformed migration filename: %s
What it means
nextSeqVersion derives the next sequence number by looking at the last existing migration filename in the directory and parsing the digits before the first underscore. If that filename has no underscore (or starts with one), the CLI cannot extract a sequence prefix and refuses to continue rather than guessing a version. This guards against mixing non-sequential files into a seq-numbered migrations directory.
Source
Thrown at internal/cli/commands.go:36
errInvalidSequenceWidth = errors.New("digits must be positive")
errIncompatibleSeqAndFormat = errors.New("the seq and format options are mutually exclusive")
errInvalidTimeFormat = errors.New("time format may not be empty")
)
func nextSeqVersion(matches []string, seqDigits int) (string, error) {
if seqDigits <= 0 {
return "", errInvalidSequenceWidth
}
nextSeq := uint64(1)
if len(matches) > 0 {
filename := matches[len(matches)-1]
matchSeqStr := filepath.Base(filename)
idx := strings.Index(matchSeqStr, "_")
if idx < 1 { // Using 1 instead of 0 since there should be at least 1 digit
return "", fmt.Errorf("malformed migration filename: %s", filename)
}
var err error
matchSeqStr = matchSeqStr[0:idx]
nextSeq, err = strconv.ParseUint(matchSeqStr, 10, 64)
if err != nil {
return "", err
}
nextSeq++
}
version := fmt.Sprintf("%0[2]*[1]d", nextSeq, seqDigits)
if len(version) > seqDigits {
return "", fmt.Errorf("next sequence number %s too large, at most %d digits are allowed", version, seqDigits)
}View on GitHub (pinned to 01a9643f14)
Solutions
- Rename the offending file(s) in the migrations directory to the standard `<seq>_<name>.<direction><ext>` format, e.g. `3_add_users.up.sql`.
- Move non-conforming files (notes, backups, timestamp-named migrations) out of the seq migrations directory.
- List files with `ls` / `filepath.Glob(dir/*<ext>)` and verify every file starts with digits followed by an underscore.
- Recreate the migration with `migrate create -seq` after cleaning the directory so the sequence can be computed.
Example fix
// before migrations/foo.up.sql // after migrations/000001_foo.up.sql
Defensive patterns
Strategy: validation
Validate before calling
files, _ := filepath.Glob(filepath.Join(dir, "*"+ext))
for _, f := range files {
base := filepath.Base(f)
idx := strings.Index(base, "_")
if idx < 1 {
return fmt.Errorf("%s must be named <digits>_<name>.<up|down>%s", f, ext)
}
if _, err := strconv.ParseUint(base[:idx], 10, 64); err != nil {
return err
}
} Type guard
func hasSeqPrefix(name string) bool {
idx := strings.Index(name, "_")
if idx < 1 {
return false
}
_, err := strconv.ParseUint(name[:idx], 10, 64)
return err == nil
} Try / catch
if err := createCmd(dir, time.Now(), format, name, ext, seq, seqDigits, print); err != nil {
if strings.Contains(err.Error(), "malformed migration filename") {
// prompt to fix/renames the offending file named in the error
}
return err
} Prevention
- Only add migrations via `migrate create -seq`, never by hand-naming files.
- Keep notes/backups/timestamp-format files outside the seq migrations directory.
- Add a CI lint that regex-checks every migration filename against ^\d+_.+\.(up|down)\.<ext$.
- Never rename a migration's numeric prefix.
When it happens
Trigger: Running `migrate create -seq ...` in a directory where the highest-matching migration file (by glob `<dir>_*<ext>`, sorted lexically) has a name without `<digits>_`, e.g. `foo.up.sql` or `_init.up.sql`.
Common situations: A hand-named migration file was dropped into the migrations folder; a file created with the default timestamp format lives next to seq files; an editor/backup file like `~` or `.bak` variants match the glob; someone renamed a migration and removed the numeric prefix.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- "%s" MigrationsTable contains too many dot characters
- next sequence number %s too large, at most %d digits are all
- duplicate migration version: %s
- digits must be positive
- the seq and format options are mutually exclusive
AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02).
Data as JSON: /api/errors/f94af73e329c7c8b.
Report an issue: GitHub.