{"record":{"id":"3fc45e5129f12672","repo":"Tencent/WeKnora","slug":"decode-extract-result-array-w","errorCode":null,"errorMessage":"decode extract_result array: %w","messagePattern":"decode extract_result array: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/mineru_cloud_converter.go","lineNumber":316,"sourceCode":"\t// Dump the raw extract_result JSON for debugging\n\trawExtract := string(pollResp.Data.ExtractResult)\n\tif len(rawExtract) > 4000 {\n\t\tlogger.Infof(context.Background(), \"[MinerUCloud] Raw extract_result (truncated to 4000 chars): %s ...\", rawExtract[:4000])\n\t} else {\n\t\tlogger.Infof(context.Background(), \"[MinerUCloud] Raw extract_result: %s\", rawExtract)\n\t}\n\n\t// Pretty-print the structure to reveal all available fields\n\tvar rawObj interface{}\n\tif err := json.Unmarshal(pollResp.Data.ExtractResult, &rawObj); err == nil {\n\t\tlogResponseStructure(\"MinerUCloud\", rawObj, \"extract_result\")\n\t}\n\n\t// The extract_result can be either a single object or an array\n\tvar items []extractResultItem\n\tif pollResp.Data.ExtractResult[0] == '[' {\n\t\tif err := json.Unmarshal(pollResp.Data.ExtractResult, &items); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decode extract_result array: %w\", err)\n\t\t}\n\t} else {\n\t\tvar single extractResultItem\n\t\tif err := json.Unmarshal(pollResp.Data.ExtractResult, &single); err != nil {\n\t\t\treturn nil, fmt.Errorf(\"decode extract_result object: %w\", err)\n\t\t}\n\t\titems = []extractResultItem{single}\n\t}\n\n\treturn items, nil\n}\n\n// extractDoneResult extracts markdown and images from a completed batch item.\n// Prefers inline markdown/content fields; falls back to downloading full_zip_url.\nfunc (c *MinerUCloudReader) extractDoneResult(_ context.Context, item *extractResultItem) (string, []types.ImageRef, error) {\n\ttext := firstNonEmpty(item.Markdown, item.Content, item.Text)\n\tif text != \"\" {\n\t\tlogger.Infof(context.Background(), \"[MinerUCloud] parsed (inline), length=%d\", len(text))","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/mineru_cloud_converter.go#L298-L334","documentation":"The extract_result field inside the poll response is a JSON string whose first character is '[', so the library tries to decode it as an array of extractResultItem; that array decode failed (mineru_cloud_converter.go:316). extract_result is a doubly-encoded JSON value, and the MinerU Cloud payload inside it did not match the expected []extractResultItem schema.","triggerScenarios":"fetchBatchStatus receives extract_result starting with '[' but its contents don't match []extractResultItem — e.g. an array of plain strings, an array with null elements, or an API change adding/removing required fields.","commonSituations":"MinerU Cloud API version change altering the extract_result item schema; a partial/failure entry serialized differently from successful entries; hand-rolled mock servers in tests returning the wrong shape.","solutions":["Dump the raw extract_result string on failure to compare against the extractResultItem struct (full_zip_url, markdown/content fields).","Update the extractResultItem struct to match the current MinerU Cloud schema (check for new/renamed fields).","Ensure array elements are objects, not strings or nulls; handle null entries defensively.","Pin/verify the MinerU Cloud API version if the contract changed unexpectedly."],"exampleFix":"// before\ntype extractResultItem struct {\n    State      string `json:\"state\"`\n    FullZipURL string `json:\"full_zip_url\"`\n}\n// after — tolerate null entries / new fields\ntype extractResultItem struct {\n    State      string `json:\"state\"`\n    FullZipURL string `json:\"full_zip_url\"`\n    Markdown   string `json:\"markdown\"`\n    Content    json.RawMessage `json:\"content\"`\n}","handlingStrategy":"type-guard","validationCode":"var raw any\nif err := json.Unmarshal(pollResp.Data.ExtractResult, &raw); err != nil {\n    return fmt.Errorf(\"extract_result is not valid JSON: %w\", err)\n}\nif _, ok := raw.([]any); !ok {\n    return errors.New(\"extract_result is not a JSON array\")\n}","typeGuard":"func isExtractResultArray(raw json.RawMessage) bool {\n    var arr []json.RawMessage\n    return json.Unmarshal(raw, &arr) == nil\n}","tryCatchPattern":"items, err := pollBatchResult(ctx, batchID)\nif err != nil {\n    if strings.Contains(err.Error(), \"decode extract_result array\") {\n        // schema drift: log raw payload and surface a contract error\n        return fmt.Errorf(\"mineru schema mismatch: %w\", err)\n    }\n    return err\n}","preventionTips":["Validate the extract_result shape (array vs object) before typed decoding.","Keep extractResultItem field tags in sync with the MinerU Cloud API version you target.","Test against realistic recorded payloads, not simplified mocks."],"tags":["json","decoding","schema","go","api-contract"],"backgroundTag":"json-schema-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}