{"record":{"id":"e6e8022933d219db","repo":"siyuan-note/siyuan","slug":"invalid-null-bazaar-index","errorCode":null,"errorMessage":"invalid null bazaar index","messagePattern":"invalid null bazaar index","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/bazaar/index.go","lineNumber":202,"sourceCode":"\tu := fmt.Sprintf(\"%s%s?t=%d\", bazaarIndexStatServer, indexPath, timeBucket)\n\tbuf := &bytes.Buffer{}\n\tresp, err := httpclient.NewBrowserRequest().SetRetryCount(0).SetContext(ctx).SetOutput(buf).Get(u)\n\tif nil != err {\n\t\treturn nil, err\n\t}\n\tif 200 != resp.StatusCode {\n\t\treturn nil, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t}\n\treturn parseBazaarIndex(buf.Bytes())\n}\n\nfunc parseBazaarIndex(data []byte) (ret *bazaarIndexSnapshot, err error) {\n\traw := map[string]json.RawMessage{}\n\tif err = json.Unmarshal(data, &raw); nil != err {\n\t\treturn nil, err\n\t}\n\tif nil == raw {\n\t\treturn nil, errors.New(\"invalid null bazaar index\")\n\t}\n\tret = &bazaarIndexSnapshot{\n\t\tpackages:    map[string]*bazaarIndexPackage{},\n\t\tlegacyStats: map[string]*bazaarStats{},\n\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}","sourceCodeStart":184,"sourceCodeEnd":220,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/bazaar/index.go#L184-L220","documentation":"parseBazaarIndex requires the fetched index to be a non-empty JSON object. json.Unmarshal into map[string]json.RawMessage succeeded, but the resulting map is nil/empty (e.g. body was literal \"null\", empty, or whitespace-only), so there is no bazaar index content at all. The library rejects such a body instead of treating it as an empty marketplace.","triggerScenarios":"fetchBazaarIndexPath receives HTTP 200 with a body that unmarshals into a nil map — literally \"null\", an empty file served with 200, or a zero-length response.","commonSituations":"CDN serving an empty object/file during a broken deploy; a proxy returning 200 with an empty body (captive portal or intercepting middleware); misconfigured object storage publishing a null placeholder index.","solutions":["Inspect the raw bytes the CDN returns for the index URL (curl it) and fix the server-side publication so it serves a real index object","If a proxy/captive portal is returning 200 with an empty body, restore direct network access","Retry after the bazaar deploy completes; the refresh loop will fetch the corrected index","If you control the publisher, guard the deploy pipeline against uploading null/empty index files"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// validate the body before trusting the index\nvar probe map[string]json.RawMessage\nif json.Unmarshal(body, &probe) != nil || len(probe) == 0 {\n    return errors.New(\"empty or null index body\")\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"invalid null bazaar index\") {\n    // 200 with empty/null body: treat as upstream publish failure, keep cached index\n}","preventionTips":["Server-side: never publish a null/empty index file; validate output before upload","Watch for proxies that return 200 with empty bodies and bypass them for the bazaar host","Keep the previous good snapshot and only swap in a new index after it parses"],"tags":["json","marketplace","validation"],"backgroundTag":"empty-response-body","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}