{"record":{"id":"9c0ac7063d158e79","repo":"GopeedLab/gopeed","slug":"extension-version-is-required","errorCode":null,"errorMessage":"extension version is required","messagePattern":"extension version is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/download/extension.go","lineNumber":444,"sourceCode":"\tDisabled bool `json:\"disabled\"`\n\n\tDevMode bool `json:\"devMode\"`\n\t// DevPath is the local path of extension source code\n\tDevPath string `json:\"devPath\"`\n\n\tCreatedAt time.Time `json:\"createdAt\"`\n\tUpdatedAt time.Time `json:\"updatedAt\"`\n}\n\nfunc (e *Extension) validate() error {\n\tif e.Name == \"\" {\n\t\treturn fmt.Errorf(\"extension name is required\")\n\t}\n\tif e.Title == \"\" {\n\t\treturn fmt.Errorf(\"extension title is required\")\n\t}\n\tif e.Version == \"\" {\n\t\treturn fmt.Errorf(\"extension version is required\")\n\t}\n\treturn nil\n}\n\nfunc (e *Extension) buildIdentity() string {\n\tif e.Author == \"\" {\n\t\treturn e.Name\n\t}\n\treturn e.Author + \"@\" + e.Name\n}\n\nfunc (e *Extension) buildInstallUrl() string {\n\tif e.Repository == nil || e.Repository.Url == \"\" {\n\t\treturn \"\"\n\t}\n\trepoUrl := e.Repository.Url\n\tif e.Repository.Directory != \"\" {\n\t\tif strings.HasSuffix(repoUrl, \"/\") {","sourceCodeStart":426,"sourceCodeEnd":462,"githubUrl":"https://github.com/GopeedLab/gopeed/blob/7b7327ffb30816273a74b142cccc0bc10c5a4c67/pkg/download/extension.go#L426-L462","documentation":"Extension.validate() requires a non-empty version in manifest.json, checked last (after name and title). The version drives UpgradeCheckExtension/UpgradeExtension comparisons (tempExt.Version != ext.Version), so an empty version would make upgrade detection meaningless and is rejected at install time.","triggerScenarios":"manifest.json missing the \"version\" key or with \"version\": \"\"; a semver-like key misspelled (\"ver\", \"v\"); version nested inside a metadata object that the flat Extension struct does not read.","commonSituations":"First publish of an extension where the author filled identity fields but not version; templates using a placeholder token that was substituted to empty; CI-generated manifests with an unset version variable.","solutions":["Add a semver-compatible \"version\" (e.g. \"1.0.0\") to manifest.json","If the manifest is generated, make the pipeline fail when the version variable is empty","Bump the version on every published change so upgrade checks detect it"],"exampleFix":"// before (manifest.json)\n{ \"name\": \"my-extension\", \"title\": \"My Extension\" }\n// after\n{ \"name\": \"my-extension\", \"title\": \"My Extension\", \"version\": \"1.0.0\" }","handlingStrategy":"validation","validationCode":"// Go: pre-validate manifest version (needed for upgrade checks)\nvar m map[string]any\n_ = json.Unmarshal(raw, &m)\nif s, _ := m[\"version\"].(string); strings.TrimSpace(s) == \"\" {\n    return fmt.Errorf(\"manifest.json: 'version' is required (e.g. 1.0.0)\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set a semver version from the first release onward","Fail CI when the version variable in generated manifests is empty","Bump version on every change so UpgradeCheckExtension can detect updates"],"tags":["extension","manifest","validation","versioning","install"],"backgroundTag":null,"analyzedSha":"7b7327ffb30816273a74b142cccc0bc10c5a4c67","analyzedAt":"2026-08-16T02:51:03.250Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}