{"record":{"id":"6f8e5a6853c2feff","repo":"siyuan-note/siyuan","slug":"incomplete-bazaar-index-metadata","errorCode":null,"errorMessage":"incomplete bazaar index metadata","messagePattern":"incomplete bazaar index metadata","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/bazaar/index.go","lineNumber":225,"sourceCode":"\t}\n\n\tmetaRaw, hasMeta := raw[\"meta\"]\n\tpackagesRaw, hasPackages := raw[\"packages\"]\n\tif hasMeta {\n\t\tif err = json.Unmarshal(metaRaw, &ret.meta); nil != err {\n\t\t\treturn nil, err\n\t\t}\n\t\tif 2 > ret.meta.Schema {\n\t\t\treturn nil, fmt.Errorf(\"invalid bazaar index schema: %d\", ret.meta.Schema)\n\t\t}\n\t\tif \"\" == strings.TrimSpace(ret.meta.Generation) || 1 > ret.meta.PublishedAt {\n\t\t\treturn nil, errors.New(\"invalid bazaar index generation metadata\")\n\t\t}\n\t\tif bazaarIndexSchema < ret.meta.Schema {\n\t\t\tret.meta.RatingsAvailable = false\n\t\t} else {\n\t\t\tif !hasPackages {\n\t\t\t\treturn nil, errors.New(\"incomplete bazaar index metadata\")\n\t\t\t}\n\t\t\tif err = json.Unmarshal(packagesRaw, &ret.packages); nil != err {\n\t\t\t\treturn nil, err\n\t\t\t}\n\t\t\tif nil == ret.packages {\n\t\t\t\treturn nil, errors.New(\"invalid bazaar index packages\")\n\t\t\t}\n\t\t\tfor packageName, pkg := range ret.packages {\n\t\t\t\tif !IsValidPackageName(packageName) || nil == pkg || !isValidBazaarRepo(pkg.Repo) || 0 > pkg.Downloads {\n\t\t\t\t\treturn nil, fmt.Errorf(\"invalid bazaar index package: %s\", packageName)\n\t\t\t\t}\n\t\t\t\tif nil != pkg.Rating {\n\t\t\t\t\trating, valid := normalizePackageRating(pkg.Rating)\n\t\t\t\t\tif !valid {\n\t\t\t\t\t\treturn nil, fmt.Errorf(\"invalid bazaar package rating: %s\", packageName)\n\t\t\t\t\t}\n\t\t\t\t\tpkg.Rating = rating\n\t\t\t\t}","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/bazaar/index.go#L207-L243","documentation":"A schema-2-or-compatible index must contain a \"packages\" key alongside \"meta\". When meta is present and its schema is within the client's supported range, but the top-level object has no \"packages\" entry, the parser rejects the index as incomplete — the package listing is the core payload of the index.","triggerScenarios":"parseBazaarIndex gets an object like {\"meta\": {...}} with schema 2..bazaarIndexSchema and no \"packages\" key; also triggered when \"packages\" is present without \"meta\" (the else-if branch at index.go:247 returns the same message).","commonSituations":"A partially written index uploaded by the publisher (meta updated, packages section dropped); a test fixture with meta only; an aggregation step on the server that failed to serialize the packages map.","solutions":["Regenerate and republish the index including both meta and a non-null packages object","Add a server-side publish check that both top-level keys exist before upload","If running a mirror/mock, copy a complete upstream index instead of a meta-only snippet","Retry later — the client refresh loop will pick up a corrected index"],"exampleFix":"// before\n{\"meta\": {\"schema\": 2, \"generation\": \"g\", \"publishedAt\": 1}}\n// after\n{\"meta\": {\"schema\": 2, \"generation\": \"g\", \"publishedAt\": 1}, \"packages\": {\"some-plugin\": {...}}}","handlingStrategy":"validation","validationCode":"// ensure both top-level keys exist before trusting/publishing an index\nvar keys map[string]json.RawMessage\njson.Unmarshal(body, &keys)\nif _, ok := keys[\"meta\"]; !ok || !strings.Contains(string(keys[\"meta\"]), \"schema\") || _, has := keys[\"packages\"]; !has {\n    return errors.New(\"index must contain meta and packages\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"incomplete bazaar index metadata\") {\n    // keep cached snapshot; the published index is missing a required section\n}","preventionTips":["Publish meta and packages atomically — build the complete object then upload once","Add a post-publish smoke test that fetches the index and asserts both keys","For mirrors, copy whole upstream indexes rather than partial sections"],"tags":["marketplace","schema","validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}