{"record":{"id":"8b75f48c1fc44953","repo":"siyuan-note/siyuan","slug":"create-session-dir-failed-w","errorCode":null,"errorMessage":"create session dir failed: %w","messagePattern":"create session dir failed: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"kernel/agent/session.go","lineNumber":415,"sourceCode":"\t\t\t\treturn currentRevision, nil, err\n\t\t\t}\n\t\t} else if currentCommittedTurnID != commitTurnID {\n\t\t\treturn currentRevision, nil, ErrSessionConflict\n\t\t}\n\t}\n\n\tnewRevision := currentRevision + 1\n\tnewData[\"revision\"] = newRevision\n\tif commitTurnID != \"\" {\n\t\tnewData[\"lastCommittedTurnID\"] = commitTurnID\n\t}\n\tdata, err = gulu.JSON.MarshalIndentJSON(newData, \"\", \"\\t\")\n\tif err != nil {\n\t\treturn currentRevision, nil, fmt.Errorf(\"encode session data failed: %w\", err)\n\t}\n\n\tif err := os.MkdirAll(dir, 0755); err != nil {\n\t\treturn currentRevision, nil, fmt.Errorf(\"create session dir failed: %w\", err)\n\t}\n\tif err := filelock.WriteFile(path, data); err != nil {\n\t\treturn currentRevision, nil, fmt.Errorf(\"save session file failed: %w\", err)\n\t}\n\tif commitTurnID != \"\" {\n\t\tif err := markRuntimeCommittedLocked(meta.ID, commitTurnID); err != nil {\n\t\t\tlogging.LogWarnf(\"commit agent runtime failed: %s\", err)\n\t\t}\n\t}\n\n\ttitle, _ := newData[\"title\"].(string)\n\tif title == \"\" {\n\t\ttitle = \"AI Agent\"\n\t}\n\tcreatedAt := meta.CreatedAt\n\tif value := numberToInt64(newData[\"createdAt\"]); value > 0 {\n\t\tcreatedAt = value\n\t}","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/afa823b6b4e4f183511e0bc0a3be93caa94c7c97/kernel/agent/session.go#L397-L433","documentation":"SaveSessionState creates the per-session directory data/storage/ai/agent/sessions/<id>/ before writing session.json (kernel/agent/session.go:414-415). os.MkdirAll failure is wrapped as 'create session dir failed'. Since the id already passed the 20-char [0-9a-z] gate, a failure here is environmental: permissions, read-only filesystem, or a non-directory occupying the path.","triggerScenarios":"First save of a new session when the workspace or storage/ai/agent tree is not writable (EACCES/EROFS), the workspace volume is full or unmounted (ENOSPC/ENXIO), or a file named exactly like the session id exists under sessions/ (ENOTDIR/EEXIST).","commonSituations":"Workspace on a read-only mount (Docker with ro volume, locked snapshot); kernel run as a different user than the one owning the workspace; leftover artifact where the directory should be; CI environments writing into a container path with a small tmpfs.","solutions":["Check the wrapped errno: EACCES → chmod/chown workspace/data/storage/ai/agent; EROFS → remount workspace read-write; ENOSPC → free space","Remove any regular file at data/storage/ai/agent/sessions/<id> so MkdirAll can create the directory","Verify with `sudo -u <kernel-user> mkdir -p` that the path is creatable","Retry the identical save once the environment is fixed — no partial state was written"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight writability probe\n// test -w <workspace>/data/storage/ai/agent && echo writable","typeGuard":"null","tryCatchPattern":"catch (e) {\n  if (/create session dir failed/.test(e?.data?.msg ?? '')) {\n    // check errno: EACCES/EROFS/ENOSPC; fix mount/ownership; remove file blocking the dir name; retry\n  }\n}","preventionTips":["Ensure the workspace is on a writable mount with space headroom","Never pre-create a regular file named like a session id under sessions/"],"tags":["agent","session","filesystem","mkdir"],"backgroundTag":"directory-creation-failed","analyzedSha":"afa823b6b4e4f183511e0bc0a3be93caa94c7c97","analyzedAt":"2026-08-18T17:04:10.865Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}