{"record":{"id":"35f4f463be7327df","repo":"semaphoreui/semaphore","slug":"migration-version-is-empty","errorCode":null,"errorMessage":"migration version is empty","messagePattern":"migration version is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db/Migration.go","lineNumber":145,"sourceCode":"\t\t{Version: \"2.18.4\"},\n\t\t{Version: \"2.18.5\"},\n\t\t{Version: \"2.18.6\"},\n\t\t{Version: \"2.18.7\"},\n\t\t{Version: \"2.18.15\"},\n\t\t{Version: \"2.19.2\"},\n\t\t{Version: \"2.19.11\"},\n\t\t{Version: \"2.19.12\"},\n\t\t{Version: \"2.19.14\"},\n\t\t{Version: \"2.20.0\"},\n\t\t{Version: \"2.20.1\"},\n\t}\n\n\treturn append(initScripts, commonScripts...)\n}\n\nfunc (m Migration) Validate() error {\n\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","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/semaphoreui/semaphore/blob/1774ccb71a0a8b82eb74ea24c23ac9ab713de2fa/db/Migration.go#L127-L163","documentation":"Migration.Validate requires a Migration to carry a non-empty Version string. Database migrations are identified and ordered by their dotted version string; an empty version cannot be tracked in the migrations table, so migrations load/init code rejects it before any comparison or execution.","triggerScenarios":"A migration source (embedded FS, filesystem scan, or programmatically constructed Migration struct) yields a Migration with Version == \"\", which is then validated during schema maintenance (migration listing/application path).","commonSituations":"A migration file named without the expected version prefix; an embedded-migrations glob matching a non-migration file; code constructing Migration{} without setting Version; packaging/build stripping migration metadata.","solutions":["Ensure every migration file/record carries a version in its name or Version field (e.g. \"1.0\")","Check the migration loading/glob code so only properly named migration files are collected","When constructing migrations programmatically, always set Version before Validate"],"exampleFix":"// before\nm := db.Migration{Script: \"INSERT ...\"}\nif err := m.Validate(); err != nil { ... }\n// after\nm := db.Migration{Version: \"1.5\", Script: \"INSERT ...\"}\nif err := m.Validate(); err != nil { ... }","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(m.Version) == \"\" {\n\treturn errors.New(\"migration must have a non-empty version\")\n}","typeGuard":"func hasVersion(m db.Migration) bool {\n\treturn strings.TrimSpace(m.Version) != \"\"\n}","tryCatchPattern":"if err := m.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"migration version is empty\") {\n\t\treturn fmt.Errorf(\"bad migration: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Enforce versioned migration file naming in CI linting","Check migration loader globs so only valid versioned files are picked up","Always set Version when constructing Migration structs in code"],"tags":["go","database","migrations","validation"],"backgroundTag":"empty-required-field","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"}