{"record":{"id":"4a348f7dea341c0e","repo":"usememos/memos","slug":"internal-4a348f","errorCode":"Internal","errorMessage":"all instance stats subtasks failed","messagePattern":"all instance stats subtasks failed","errorType":"exception","errorClass":null,"httpStatus":500,"severity":"error","filePath":"server/router/api/v1/instance_stats.go","lineNumber":128,"sourceCode":"\tg.Go(func() error {\n\t\tsize, err := walkLocalStorage(s.Profile.Data)\n\t\tif err != nil {\n\t\t\trecord(\"local_storage\", err)\n\t\t\treturn nil\n\t\t}\n\t\tstats.LocalStorageBytes = size\n\t\treturn nil\n\t})\n\n\t_ = g.Wait()\n\n\tfor _, r := range results {\n\t\tslog.Warn(\"instance stats subtask failed\", slog.String(\"subtask\", r.name), slog.String(\"err\", r.err.Error()))\n\t}\n\n\tconst totalSubtasks = 2\n\tif len(results) == totalSubtasks {\n\t\treturn nil, errors.New(\"all instance stats subtasks failed\")\n\t}\n\treturn stats, nil\n}\n\n// walkLocalStorage returns the recursive size of dir in bytes.\n// Symlinks are not followed; per-entry errors below the root are ignored\n// (the walk continues). An error accessing the root itself is returned.\nfunc walkLocalStorage(dir string) (int64, error) {\n\tif dir == \"\" {\n\t\treturn -1, errors.New(\"empty data directory\")\n\t}\n\tvar total int64\n\terr := filepath.WalkDir(dir, func(path string, entry os.DirEntry, walkErr error) error {\n\t\tif walkErr != nil {\n\t\t\tif path == dir {\n\t\t\t\t// Root itself is inaccessible — abort the walk.\n\t\t\t\treturn walkErr\n\t\t\t}","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/usememos/memos/blob/14d757ce1fb31c78590f374bc042f8dbedbc20d7/server/router/api/v1/instance_stats.go#L110-L146","documentation":"GetInstanceStats fans out two concurrent subtasks (host/system stats and local-storage size walk) via an errgroup, collecting per-subtask results. If BOTH fail (len(results) == totalSubtasks), the whole RPC fails with this Internal error; each individual failure is also logged as a slog.Warn. Partial success still returns a stats object.","triggerScenarios":"Host stats collection errors (os.Hostname, boot time, or sysinfo failure) AND the local data directory walk fails (e.g. empty/unusable data dir, permission denied at the root) in the same call.","commonSituations":"The instance data directory was moved, unmounted, or made unreadable by the running user; container with an inaccessible volume mount; exotic host where sysinfo cannot read kernel stats; disk full or fs errors during the recursive walk.","solutions":["Check the server logs for the two 'instance stats subtask failed' warn lines naming the exact subtask errors.","Verify the memos data directory exists and is readable/writable by the process user (check DATA variable / --data flag).","If running in Docker, confirm the volume is mounted correctly and not read-only.","If only one subtask failed, stats still return; harden or fix that specific collector instead of the whole RPC."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  stats = await getInstanceStats({});\n} catch (e) {\n  if (e.code === 'internal' && e.message.includes('all instance stats subtasks failed')) {\n    // transient fs/host issues can clear; retry once after a short delay, then surface\n    stats = await retryOnce(getInstanceStats, {});\n  } else throw e;\n}","preventionTips":["Monitor server logs for 'instance stats subtask failed' to catch the first failing subtask early.","Health-check the data directory (exists, readable, writable) in deployment probes.","Run the memos process as a user with access to the mounted data volume."],"tags":["internal","instance-stats","errgroup","filesystem"],"backgroundTag":null,"analyzedSha":"14d757ce1fb31c78590f374bc042f8dbedbc20d7","analyzedAt":"2026-08-15T09:27:36.538Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}