{"record":{"id":"7da5e1b326472deb","repo":"siyuan-note/siyuan","slug":"conf-language-199-7da5e1","errorCode":null,"errorMessage":"Conf.Language(199)","messagePattern":"Conf\\.Language\\(199\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/notebook_bundle.go","lineNumber":218,"sourceCode":"\n// ImportSYNotebookBundle 导入批量笔记本包。普通 .sy.zip 返回 bundle=false，由原有导入流程继续处理。\nfunc ImportSYNotebookBundle(zipPath string) (boxIDs []string, bundle bool, err error) {\n\tarchive, openErr := zip.OpenReader(zipPath)\n\tif nil != openErr {\n\t\terr = openErr\n\t\treturn\n\t}\n\tvar manifestData []byte\n\trootName := \"\"\n\tmanifestSuffix := \"/\" + syNotebookBundleManifestPath\n\tfor _, file := range archive.File {\n\t\tif !strings.HasSuffix(file.Name, manifestSuffix) {\n\t\t\tcontinue\n\t\t}\n\t\tcandidateRoot := strings.TrimSuffix(file.Name, manifestSuffix)\n\t\tif candidateRoot == \"\" || strings.Contains(candidateRoot, \"/\") || rootName != \"\" {\n\t\t\t_ = archive.Close()\n\t\t\treturn nil, true, errors.New(Conf.Language(199))\n\t\t}\n\t\treader, readErr := file.Open()\n\t\tif nil != readErr {\n\t\t\t_ = archive.Close()\n\t\t\treturn nil, true, readErr\n\t\t}\n\t\tmanifestData, readErr = io.ReadAll(reader)\n\t\t_ = reader.Close()\n\t\tif nil != readErr {\n\t\t\t_ = archive.Close()\n\t\t\treturn nil, true, readErr\n\t\t}\n\t\trootName = candidateRoot\n\t}\n\t_ = archive.Close()\n\tif rootName == \"\" {\n\t\treturn nil, false, nil\n\t}","sourceCodeStart":200,"sourceCodeEnd":236,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/kernel/model/notebook_bundle.go#L200-L236","documentation":"ImportSYNotebookBundle imports a multi-notebook bundle (.sy.zip containing a bundle manifest). While scanning the archive for a `*/manifest.json` bundle entry, it found a manifest path that is structurally invalid: the candidate root folder is empty, nested (contains '/'), or a second manifest was found after one was already accepted. The library rejects such archives because a bundle must contain exactly one top-level folder holding exactly one manifest.","triggerScenarios":"Calling ImportSYNotebookBundle (via the import .sy.zip API endpoint) on a zip where: (a) the manifest sits at the archive root (candidateRoot == \"\", e.g. 'manifest.json' with no folder prefix is matched by suffix '/manifest.json'? actually an entry named exactly with empty prefix), (b) a manifest exists in a nested subfolder like 'outer/inner/manifest.json', or (c) the zip contains two or more manifest files in different top-level folders.","commonSituations":"Hand-assembled or re-zipped bundles where the zip tool wrapped folders twice (e.g. 'Bundle/Bundle/manifest.json'), bundles produced by old/custom export scripts that place the manifest at the archive root, or concatenated archives that accidentally include manifests from multiple exports.","solutions":["Rebuild the bundle so the zip contains exactly one top-level folder with manifest.json directly inside it and no other manifest.json anywhere in the archive","Open the .sy.zip and inspect entry names (unzip -l) to find duplicate or nested manifest.json files and remove the extras","Re-export the bundle from SiYuan's export-bundle feature instead of manually repackaging","If the file is a plain single-notebook .sy.zip (no manifest), do not call ImportSYNotebookBundle; use the normal single-notebook import path, which is tried when bundle=false"],"exampleFix":"// before: zip layout 'outer/inner/manifest.json' or two manifests\n// after: exactly one root folder\n// bundle/\n//   manifest.json\n//   notebooks/Notebook1.sy.zip","handlingStrategy":"validation","validationCode":"// Inspect zip entries before import (Node.js example)\nconst entries = (await getZipEntryNames(bundlePath));\nconst manifests = entries.filter(n => n.endsWith('/manifest.json'));\nif (manifests.length !== 1) throw new Error('bundle must contain exactly one manifest');\nconst root = manifests[0].slice(0, -('/manifest.json'.length));\nif (!root || root.includes('/')) throw new Error('manifest must sit in a single top-level folder');","typeGuard":null,"tryCatchPattern":"try {\n  const { boxIDs, bundle } = await importSYNotebookBundle(zipPath);\n  if (!bundle) return importSingleNotebook(zipPath); // bundle=false means plain .sy.zip\n} catch (e) {\n  if (e.message.includes('invalid') || isLocalizedBundleError(e)) showUserHint('Rebuild the bundle: exactly one top-level folder with one manifest.json');\n  else throw e;\n}","preventionTips":["Always create bundles with SiYuan's built-in export instead of manual re-zipping","Run unzip -l and grep for manifest.json occurrences; expect exactly one","Never nest bundle folders inside bundle folders when redistributing"],"tags":["import","zip-archive","bundle-manifest","validation"],"backgroundTag":"invalid-argument-format","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"}