{"record":{"id":"7d870a11fe60bd04","repo":"siyuan-note/siyuan","slug":"target-notebook-required","errorCode":null,"errorMessage":"target notebook required","messagePattern":"target notebook required","errorType":"validation","errorClass":"ErrSYTargetNotebookRequired","httpStatus":null,"severity":"warning","filePath":"kernel/model/import.go","lineNumber":148,"sourceCode":"\t\t\tif strings.HasPrefix(dest, \"data:image\") && strings.Contains(dest, \";base64,\") {\n\t\t\t\tprocessBase64Img(n, dest, assetDirPath, boxID)\n\t\t\t}\n\t\t}\n\t\treturn ast.WalkContinue\n\t})\n\treturn\n}\n\nfunc ImportSY(zipPath, boxID, toPath string) (err error) {\n\t_, err = importSY(zipPath, boxID, toPath, false, false)\n\treturn\n}\n\nfunc ImportSYNotebook(zipPath string) (boxID string, err error) {\n\treturn importSY(zipPath, \"\", \"/\", true, false)\n}\n\nvar ErrSYTargetNotebookRequired = errors.New(\"target notebook required\")\n\nfunc ImportSYAuto(zipPath, boxID, toPath string) (createdBoxID string, notebook bool, err error) {\n\tcreatedBoxID, err = importSY(zipPath, boxID, toPath, false, true)\n\tnotebook = err == nil && createdBoxID != boxID\n\treturn\n}\n\nfunc isSYNotebookExport(hasBoxConf, hasBoxDocMeta bool) bool {\n\treturn hasBoxConf || hasBoxDocMeta\n}\n\nfunc importSY(zipPath, boxID, toPath string, createNotebook, autoDetect bool) (createdBoxID string, err error) {\n\tutil.PushEndlessProgress(Conf.Language(73))\n\tdefer util.ClearPushProgress(100)\n\n\tlockSync()\n\tdefer unlockSync()\n","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/import.go#L130-L166","documentation":"ErrSYTargetNotebookRequired (import.go:148) is a sentinel returned by importSY when autoDetect is true, the archive does not look like a notebook export (no .siyuan/conf.json and no boxDocMeta), and the caller did not supply a boxID. ImportSYAuto uses it to signal the API layer that it must ask the user for a target notebook; api/import.go:142 catches it via errors.Is and stages the upload for a follow-up continueImportSY call.","triggerScenarios":"POST /api/import/importSYAuto with no \"notebook\" field for an archive that contains only document(s) (not a notebook export). The handler responds with {type:\"document\", token:...} and the client must call /api/import/continueImportSY with a chosen notebook.","commonSituations":"User drops a .sy.zip exported from a single doc (not a notebook) into the auto-import dropzone; the archive's .siyuan/conf.json was stripped during transfer; the export predates the notebook-metadata feature.","solutions":["On the client, when /api/import/importSYAuto returns a token, prompt the user to pick a notebook and call /api/import/continueImportSY with {token, notebook}.","If the caller already knows the target, call /api/import/importSY directly with the notebook field instead of importSYAuto.","Detect notebook-vs-document archives upstream by checking for .siyuan/conf.json before choosing the import entry point."],"exampleFix":"// before\ncreated, notebook, err := model.ImportSYAuto(zip, \"\", \"/\")\n\n// after\ncreated, notebook, err := model.ImportSYAuto(zip, \"\", \"/\")\nif errors.Is(err, model.ErrSYTargetNotebookRequired) {\n    token := stageSYImport(zip)\n    // ask user for notebook, then continueImportSY(token, notebook)\n}","handlingStrategy":"try-catch","validationCode":"// If you already know the target notebook, call ImportSY directly:\n//   model.ImportSY(zipPath, boxID, toPath)\n// Otherwise only use ImportSYAuto and handle the sentinel.","typeGuard":null,"tryCatchPattern":"created, notebook, err := model.ImportSYAuto(zipPath, boxID, toPath)\nif errors.Is(err, model.ErrSYTargetNotebookRequired) {\n    token, _ := stageSYImport(zipPath)\n    // prompt user for notebook, then continueImportSY(token, chosenNotebook)\n    return\n}","preventionTips":["When the target notebook is known, prefer /api/import/importSY with an explicit notebook field.","On the client, handle the {type:\"document\", token} response by opening the notebook picker.","Detect notebook-vs-document archives by checking for .siyuan/conf.json upstream."],"tags":["import","sy-zip","sentinel-error","api-flow"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}