{"record":{"id":"ddbd654367ea3165","repo":"Tencent/WeKnora","slug":"no-md-file-found-in-zip","errorCode":null,"errorMessage":"no .md file found in zip","messagePattern":"no \\.md file found in zip","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/infrastructure/docparser/mineru_cloud_converter.go","lineNumber":389,"sourceCode":"\t\treturn \"\", nil, fmt.Errorf(\"read zip body: %w\", err)\n\t}\n\n\tzr, err := zip.NewReader(bytes.NewReader(zipData), int64(len(zipData)))\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"open zip: %w\", err)\n\t}\n\n\t// Find .md files\n\tvar mdFiles []string\n\tentries := make(map[string]*zip.File)\n\tfor _, f := range zr.File {\n\t\tentries[f.Name] = f\n\t\tif strings.HasSuffix(f.Name, \".md\") {\n\t\t\tmdFiles = append(mdFiles, f.Name)\n\t\t}\n\t}\n\tif len(mdFiles) == 0 {\n\t\treturn \"\", nil, fmt.Errorf(\"no .md file found in zip\")\n\t}\n\tsort.Slice(mdFiles, func(i, j int) bool {\n\t\tdi, dj := strings.Count(mdFiles[i], \"/\"), strings.Count(mdFiles[j], \"/\")\n\t\tif di != dj {\n\t\t\treturn di < dj\n\t\t}\n\t\treturn mdFiles[i] < mdFiles[j]\n\t})\n\n\tmdText, err := readZipEntry(entries[mdFiles[0]])\n\tif err != nil {\n\t\treturn \"\", nil, fmt.Errorf(\"read md file: %w\", err)\n\t}\n\n\tmdDir := filepath.Dir(mdFiles[0])\n\n\t// Extract referenced images\n\tvar imageRefs []types.ImageRef","sourceCodeStart":371,"sourceCodeEnd":407,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/infrastructure/docparser/mineru_cloud_converter.go#L371-L407","documentation":"The downloaded ZIP contains no file ending in .md, but the MinerU cloud converter requires exactly such a Markdown file to extract the parsed document text. The ZIP opened fine; its contents don't match the expected output layout.","triggerScenarios":"extractDoneResult downloads a job's result ZIP whose entries contain only images/JSON (e.g. layout.json, *_content_list.json) and no *.md entry.","commonSituations":"MinerU server version or config change (output format toggled, markdown disabled or renamed to .markdown); job failed server-side and an empty/partial archive was uploaded; polling endpoint returned the wrong artifact (e.g. input echo instead of result).","solutions":["Log the ZIP entry list (zr.File names) to confirm what MinerU actually returned.","Check the MinerU deployment's output options — ensure Markdown output is enabled and the version matches what this converter expects.","If needed, broaden the suffix match (e.g. also accept .markdown) or use the content_list JSON as a fallback source.","Verify the job's status/progress field before treating the ZIP as a finished result."],"exampleFix":"// before\nif len(mdFiles) == 0 {\n    return \"\", nil, fmt.Errorf(\"no .md file found in zip\")\n}\n// after\nif len(mdFiles) == 0 {\n    names := make([]string, 0, len(entries))\n    for n := range entries {\n        names = append(names, n)\n    }\n    return \"\", nil, fmt.Errorf(\"no .md file found in zip (entries: %v)\", names)\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"md, _, err := conv.Read(ctx, req)\nif err != nil && strings.Contains(err.Error(), \"no .md file found in zip\") {\n    // fall back to content_list JSON or surface a clear parse-failure to the caller\n    return handleMissingMarkdown(err)\n}","preventionTips":["Pin and test against the MinerU server version your converter expects","Log ZIP entry names on every failure to detect output-format drift early","Keep an integration test that parses a fixture document end-to-end","Alert on this error rate — it usually means a server-side config change"],"tags":["zip","missing-file","mineru","contract-mismatch"],"backgroundTag":"missing-expected-file","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}