{"record":{"id":"2954360a7f38325d","repo":"siyuan-note/siyuan","slug":"this-is-not-a-valid-sy-zip-archive-if-the-archiv","errorCode":null,"errorMessage":"This is not a valid .sy.zip archive. If the archive was exported from [Settings], please import it from [Settings]","messagePattern":"This is not a valid \\.sy\\.zip archive\\. If the archive was exported from \\[Settings\\], please import it from \\[Settings\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/import.go","lineNumber":206,"sourceCode":"\t\t\treturn err\n\t\t}\n\t\tif d == nil {\n\t\t\treturn nil\n\t\t}\n\t\tif !d.IsDir() && strings.HasSuffix(d.Name(), \".sy\") {\n\t\t\tsyPaths = append(syPaths, path)\n\t\t}\n\t\treturn nil\n\t})\n\n\tentries, err := os.ReadDir(unzipPath)\n\tif err != nil {\n\t\tlogging.LogErrorf(\"read unzip dir [%s] failed: %s\", unzipPath, err)\n\t\treturn\n\t}\n\tif 1 != len(entries) || !entries[0].IsDir() {\n\t\tlogging.LogErrorf(\"invalid .sy.zip [%v]\", entries)\n\t\terr = errors.New(Conf.Language(199))\n\t\treturn\n\t}\n\tunzipRootPath := filepath.Join(unzipPath, entries[0].Name())\n\tname := filepath.Base(unzipRootPath)\n\tif strings.HasPrefix(name, \"data-20\") && len(\"data-20230321175442\") == len(name) {\n\t\tlogging.LogErrorf(\"invalid .sy.zip [unzipRootPath=%s, baseName=%s]\", unzipRootPath, name)\n\t\terr = errors.New(Conf.Language(199))\n\t\treturn\n\t}\n\tvar importedBoxConf *conf.BoxConf\n\timportedConfPath := filepath.Join(unzipRootPath, \".siyuan\", \"conf.json\")\n\thasImportedBoxConf := filelock.IsExist(importedConfPath)\n\tvar importedMetadataErr error\n\tif hasImportedBoxConf {\n\t\tconfData, readErr := filelock.ReadFile(importedConfPath)\n\t\tif readErr == nil {\n\t\t\timportedBoxConf = conf.NewBoxConf()\n\t\t\tif unmarshalErr := gulu.JSON.UnmarshalJSON(confData, importedBoxConf); unmarshalErr != nil {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/import.go#L188-L224","documentation":"After unzipping, importSY0 requires the archive root to contain exactly one entry and that entry to be a directory (the exported notebook/document folder). Any other top-level layout fails the '1 != len(entries) || !entries[0].IsDir()' guard and is rejected with the generic invalid-archive message Language(199). The actual entries are logged via LogErrorf for diagnosis.","triggerScenarios":"Any importSY-family call with a zip whose top level has zero entries, more than one entry, or a file at the root: hand-built zips that selected the folder's contents instead of the folder, archives re-packed by mail/cloud tools that flattened the root, double-zipped archives, or an empty zip.","commonSituations":"User right-clicks the exported folder and zips selected files, losing the single-root layout. A transfer service re-packs attachments. The user actually has a full Data export (see also error 802) or a Markdown archive, not a .sy.zip.","solutions":["Re-export from the source via right-click notebook/document - Export - .sy.zip; SiYuan always produces the correct single root folder","If repacking manually, ensure the zip has exactly one top-level directory containing the .sy files and .siyuan metadata","If the archive is really a Data export, import it from Settings - Import - Data instead; if it is Markdown, use /api/import/importStdMd"],"exampleFix":"# before: zip of the folder contents (multiple/dangling root entries)\nzip -r out.zip .            # INVALID for .sy.zip import\n\n# after: zip that preserves the single root directory\nzip -r out.zip 20230321175442-xxxxxxx/   # one top-level dir holding the .sy tree","handlingStrategy":"validation","validationCode":"func hasSingleRootDir(zipPath string) bool {\n    r, err := zip.OpenReader(zipPath)\n    if err != nil {\n        return false\n    }\n    defer r.Close()\n    roots := map[string]struct{}{}\n    for _, f := range r.File {\n        name := strings.TrimPrefix(f.Name, \"./\")\n        if name == \"\" {\n            continue\n        }\n        parts := strings.SplitN(name, \"/\", 2)\n        roots[parts[0]] = struct{}{}\n    }\n    return len(roots) == 1\n}","typeGuard":"func isInvalidSYZipErr(err error) bool {\n    return err != nil && err.Error() == model.Conf.Language(199)\n}","tryCatchPattern":"if err := model.ImportSY(zipPath, boxID, toPath); err != nil {\n    if err.Error() == model.Conf.Language(199) {\n        // tell the user the archive layout is invalid; do not retry the same file\n    }\n}","preventionTips":["Always export via SiYuan itself (right-click - Export - .sy.zip) instead of zipping folders manually","When repacking, zip the folder itself, not its contents, so exactly one top-level directory exists","Programmatically verify single-root layout (as above) before submitting the file to the API"],"tags":["siyuan","import","sy-zip","zip-structure","validation"],"backgroundTag":"archive-structure-invalid","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}