{"record":{"id":"2ced26106ef4344b","repo":"semaphoreui/semaphore","slug":"invalid-migration-version-format-s","errorCode":null,"errorMessage":"invalid migration version format %s","messagePattern":"invalid migration version format (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db/Migration.go","lineNumber":162,"sourceCode":"\tif m.Version == \"\" {\n\t\treturn fmt.Errorf(\"migration version is empty\")\n\t}\n\n\treturn nil\n}\n\ntype MigrationVersion struct {\n\tMajor int\n\tMinor int\n\tPatch int\n}\n\nfunc (m Migration) ParseVersion() (res MigrationVersion, err error) {\n\n\tparts := strings.Split(m.Version, \".\")\n\n\tif len(parts) < 2 {\n\t\terr = fmt.Errorf(\"invalid migration version format %s\", m.Version)\n\t\treturn\n\t}\n\n\tres.Major, err = strconv.Atoi(parts[0])\n\tif err != nil {\n\t\terr = fmt.Errorf(\"invalid migration version major part %s\", parts[0])\n\t\treturn\n\t}\n\n\tres.Minor, err = strconv.Atoi(parts[1])\n\tif err != nil {\n\t\terr = fmt.Errorf(\"invalid migration version minor part %s\", parts[1])\n\t\treturn\n\t}\n\n\tif len(parts) < 3 {\n\t\tres.Patch = math.MaxInt\n\t\treturn","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/db/Migration.go#L144-L180","documentation":"Migration.ParseVersion splits the Version string on '.' and requires at least two parts (major.minor) to build a comparable MigrationVersion. Versions with no dot — or empty strings reaching the parser — are rejected with this formatted error, surfaced through Compare when ordering migrations.","triggerScenarios":"Comparing or sorting migrations whose Version lacks a '.', e.g. \"1\", \"v2\", \"\" (when Validate was skipped), or a version accidentally stripped of its minor part by string processing.","commonSituations":"Hand-edited migration versions like \"3\" instead of \"3.0\"; scripts renaming migration files and dropping part of the version; mixing migration sets from forks using different versioning schemes.","solutions":["Rename/redefine the migration version to include both major and minor parts (e.g. \"1.0\", \"3.2\")","Audit migration file names and the Version fields produced by the loader for missing dot separators","Keep versions strictly in major.minor (optionally patch) format matching the project's existing migration history"],"exampleFix":"// before\n// migration file: 5__add_table.sql  -> Version \"5\"\n// after\n// migration file: 5.0__add_table.sql -> Version \"5.0\"","handlingStrategy":"validation","validationCode":"if len(strings.Split(m.Version, \".\")) < 2 {\n\treturn fmt.Errorf(\"version %q must be in major.minor format\", m.Version)\n}","typeGuard":"func isDottedVersion(v string) bool {\n\treturn len(strings.Split(v, \".\")) >= 2\n}","tryCatchPattern":"if _, err := m.ParseVersion(); err != nil {\n\tif strings.Contains(err.Error(), \"invalid migration version format\") {\n\t\treturn fmt.Errorf(\"bad migration version: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Always use major.minor (optionally .patch) version strings for migrations","Call m.Validate() before ParseVersion/Compare so empty versions fail earlier","CI-check migration file names against a version regex (e.g. ^\\d+\\.\\d+(\\.\\d+)?__)"],"tags":["go","database","migrations","version-format"],"backgroundTag":"invalid-argument-format","analyzedSha":"1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa","analyzedAt":"2026-09-07T11:00:33.293Z","contentChangedAt":"2026-09-07T11:00:33.293Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}