{"record":{"id":"2637eb6aadd60931","repo":"AlistGo/alist","slug":"invalid-json","errorCode":null,"errorMessage":"invalid json","messagePattern":"invalid json","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/chunker/util.go","lineNumber":223,"sourceCode":"\t\tSize:     &size,\n\t\tChunkNum: &nChunks,\n\t\tMD5:      md5Value,\n\t\tSHA1:     sha1Value,\n\t\tXactID:   xactID,\n\t}\n\tdata, err := json.Marshal(&meta)\n\tif err == nil && len(data) >= maxMetadataSizeWrite {\n\t\treturn nil, errors.New(\"metadata can't be this big\")\n\t}\n\treturn data, err\n}\n\nfunc unmarshalMetadata(data []byte) (*chunkMetadata, error) {\n\tif len(data) > maxMetadataSizeWrite {\n\t\treturn nil, errors.New(\"metadata is too large\")\n\t}\n\tif data == nil || len(data) < 2 || data[0] != '{' || data[len(data)-1] != '}' {\n\t\treturn nil, errors.New(\"invalid json\")\n\t}\n\tvar meta metadataJSON\n\tif err := json.Unmarshal(data, &meta); err != nil {\n\t\treturn nil, err\n\t}\n\tif meta.Version == nil || meta.Size == nil || meta.ChunkNum == nil {\n\t\treturn nil, errors.New(\"missing required field\")\n\t}\n\tif *meta.Version < 1 {\n\t\treturn nil, errors.New(\"wrong version\")\n\t}\n\tif *meta.Size < 0 {\n\t\treturn nil, errors.New(\"negative file size\")\n\t}\n\tif *meta.ChunkNum < 1 || *meta.ChunkNum > maxSafeChunkNumber {\n\t\treturn nil, errors.New(\"wrong number of chunks\")\n\t}\n\tif meta.MD5 != \"\" {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/chunker/util.go#L205-L241","documentation":"unmarshalMetadata performs a cheap sanity pre-check before json.Unmarshal: the data must be at least 2 bytes and start with '{' and end with '}'. Failing this returns 'invalid json', meaning the metadata content is not a JSON object at all — truncated, empty, or garbage.","triggerScenarios":"A metadata companion file that is empty, a single byte, or whose first/last bytes are not braces — e.g. an HTML error page saved as the metadata file by a misbehaving remote, a truncated upload, or a plaintext marker written by another program. Raised whenever the chunker reads metadata for a chunked file.","commonSituations":"Remote storage returning an error page instead of file content; interrupted metadata writes; third-party tools creating similarly-named files that the chunker mistakes for metadata.","solutions":["Inspect the actual metadata file content on the remote storage to see what it really contains","Delete the corrupted chunk set (metadata + chunk files) and re-upload the original file","If an error page was stored, fix the underlying storage driver/auth issue first, then re-upload"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if len(data) < 2 || data[0] != '{' || data[len(data)-1] != '}' {\n    return fmt.Errorf(\"metadata at %s is not a JSON object; got %q\", path, truncate(data, 80))\n}","typeGuard":null,"tryCatchPattern":"meta, err := readMeta(ctx, p)\nif err != nil && strings.Contains(err.Error(), \"invalid json\") {\n    log.Printf(\"corrupt metadata for %s, first bytes: %q\", p, head(data))\n    // schedule re-upload of the file instead of retrying reads\n}","preventionTips":["Alert on non-JSON bodies — they often indicate the backend served an error page","Keep error-page detection in downstream storages (auth, Cloudflare) healthy"],"tags":["chunker","metadata","corruption","json"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}