{"record":{"id":"a0987af131a39336","repo":"siyuan-note/siyuan","slug":"duplicated-filename","errorCode":null,"errorMessage":"Duplicated filename","messagePattern":"Duplicated filename","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/file.go","lineNumber":2357,"sourceCode":"\t\tparentID := path.Base(folder)\n\t\tparentTree, loadErr := LoadTreeByBlockID(parentID)\n\t\tif nil != loadErr {\n\t\t\tlogging.LogErrorf(\"get parent tree [%s] failed\", parentID)\n\t\t\treturn nil, ErrBlockNotFound\n\t\t}\n\t\tparentPath := strings.TrimSuffix(parentTree.Path, \".sy\")\n\t\tif parentTree.Box != boxID || cleanBoxDocDir(parentPath) != cleanBoxDocDir(folder) {\n\t\t\tlogging.LogErrorf(\"parent tree [%s] does not match box [%s] and folder [%s]\", parentID, boxID, folder)\n\t\t\treturn nil, ErrBlockNotFound\n\t\t}\n\t\thPath = path.Join(parentTree.HPath, title)\n\t}\n\n\tif depth := strings.Count(p, \"/\"); 7 < depth && !Conf.FileTree.AllowCreateDeeper {\n\t\treturn nil, errors.New(Conf.Language(118))\n\t}\n\tif box.Exist(p) {\n\t\treturn nil, errors.New(Conf.Language(1))\n\t}\n\n\tret = &createDocValidation{\n\t\tbox:     box,\n\t\tpath:    p,\n\t\ttitle:   title,\n\t\thPath:   hPath,\n\t\tid:      util.GetTreeID(p),\n\t\tfolder:  folder,\n\t\tisEmpty: isEmpty,\n\t}\n\treturn\n}\n\nfunc cleanBoxDocDir(p string) string {\n\treturn path.Clean(\"/\" + strings.TrimPrefix(p, \"/\"))\n}\n","sourceCodeStart":2339,"sourceCodeEnd":2375,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/model/file.go#L2339-L2375","documentation":"The last guard in validateCreateDoc (kernel/model/file.go:2357): box.Exist(p) checks the actual filesystem, and if data/<boxID>/<p> already exists the creation fails with Conf.Language(1) (\"Duplicated filename\"). Because SiYuan paths embed the document ID, an existing file means the requested ID is already taken — either a genuinely duplicate ID or a stale/orphaned .sy file left behind after a crash or failed index rebuild.","triggerScenarios":"POST /api/filetree/createDoc / createDocWithMd reusing a path/ID that already exists (retry logic resubmitting the same generated ID, copy operations deriving paths from the source ID); or an unindexed leftover file at that path after an interrupted delete/create.","commonSituations":"Naive retry wrappers that regenerate everything except the ID; ID collisions from non-random generators; orphaned .sy files after power loss; docs created in an unopened notebook earlier by file copy.","solutions":["Generate a fresh timestamp+random ID for every create attempt (never reuse the previous ID on retry)","If you expect the path to be free, verify first: list the folder (/api/filetree/listDocsByPath) or check the block via /api/block/getBlockInfo","If a stale unindexed .sy file occupies the path, remove it (with the kernel stopped or via file API) and run a rebuild index (/api/filetree/refreshFiletree) before retrying"],"exampleFix":"// before\nlet path = `/20240101120000-fixedid1.sy`\nretry(() => fetchPost('/api/filetree/createDocWithMd', {notebook, path, markdown})) // always same path -> duplicate\n\n// after\nconst newPath = () => `/${Date.now()}...` // fresh ID each attempt\nretry(() => fetchPost('/api/filetree/createDocWithMd', {notebook, path: newPath(), markdown}))","handlingStrategy":"validation","validationCode":"// Existence pre-check via the kernel's own Box API\nif box := Conf.Box(boxID); nil != box && box.Exist(p) {\n\treturn fmt.Errorf(\"path [%s] already exists, generate a fresh ID\", p)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Regenerate the timestamp+random ID on every create retry; never pin an ID across attempts","Use strong randomness for the ID suffix — weak generators cause real collisions across clients","After crashes, look for orphaned .sy files at planned paths and clean them plus refreshFiletree"],"tags":["siyuan","create-doc","duplicate","document-id","validation"],"backgroundTag":"duplicate-path-conflict","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}