semaphoreui/semaphore · error

invalid migration version minor part

Error message

invalid migration version minor part %s

What it means

ParseVersion converts the second dot-separated segment of a migration version string to an integer for the Minor field. If strconv.Atoi fails on parts[1], it returns 'invalid migration version minor part %s'. This only happens when a second segment exists but is non-numeric.

Solutions

  1. Correct the migration version so the second segment is an integer, e.g. '1.2' instead of '1.x'
  2. Use the two-part format 'major.minor' or three-part 'major.minor.patch' with all numeric parts
  3. Validate version strings with a regex like ^\d+(\.\d+)?(\.\d+)?$ before invoking ParseVersion/Compare

Example fix

// before
m.Version = "2.beta"
// after
m.Version = "2.0"
Defensive patterns

Strategy: validation

Validate before calling

parts := strings.Split(version, ".")
if len(parts) < 2 {
    return fmt.Errorf("version %q needs a numeric minor part", version)
}
if _, err := strconv.Atoi(parts[1]); err != nil {
    return fmt.Errorf("minor part %q is not numeric", parts[1])
}

Try / catch

if err := Compare(a, b); err != nil {
    var se *strconv.NumError
    if errors.As(err, &se) || strings.Contains(err.Error(), "minor part") {
        return fmt.Errorf("fix version string: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling Compare/ParseVersion with a version like '1.x' or '1.beta' — the major part parses but the minor segment is not an integer.

Common situations: Typos in migration version strings ('1..0', '1.o'); using branch names or labels as minor versions; copying version strings from tags like '1.rc1'.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of semaphoreui/semaphore@1774ccb71a (2026-09-07). Data as JSON: /api/errors/3e17b6432b1f57a4. Report an issue: GitHub.

Appendix: source

Thrown at db/Migration.go:174

func (m Migration) ParseVersion() (res MigrationVersion, err error) {

	parts := strings.Split(m.Version, ".")

	if len(parts) < 2 {
		err = fmt.Errorf("invalid migration version format %s", m.Version)
		return
	}

	res.Major, err = strconv.Atoi(parts[0])
	if err != nil {
		err = fmt.Errorf("invalid migration version major part %s", parts[0])
		return
	}

	res.Minor, err = strconv.Atoi(parts[1])
	if err != nil {
		err = fmt.Errorf("invalid migration version minor part %s", parts[1])
		return
	}

	if len(parts) < 3 {
		res.Patch = math.MaxInt
		return
	}

	res.Patch, err = strconv.Atoi(parts[2])
	if err != nil {
		err = fmt.Errorf("invalid migration version patch part %s", parts[2])
		return
	}

	return
}

func (v MigrationVersion) Compare(o MigrationVersion) int {

View on GitHub (pinned to 1774ccb71a)