{"record":{"id":"c49a6705fec1ae41","repo":"decolua/9router","slug":"data-dir-configured-not-writable-fallback-c49a67","errorCode":null,"errorMessage":"[DATA_DIR] '${configured}' not writable → fallback ~/.${APP_NAME}","messagePattern":"\\[DATA_DIR\\] '(.+?)' not writable → fallback ~/\\.(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/mitm/paths.js","lineNumber":22,"sourceCode":"\nconst APP_NAME = \"9router\";\n\nfunction defaultDir() {\n  if (process.platform === \"win32\") {\n    return path.join(process.env.APPDATA || path.join(os.homedir(), \"AppData\", \"Roaming\"), APP_NAME);\n  }\n  return path.join(os.homedir(), `.${APP_NAME}`);\n}\n\nfunction getDataDir() {\n  const configured = process.env.DATA_DIR;\n  if (!configured) return defaultDir();\n  try {\n    fs.mkdirSync(configured, { recursive: true });\n    return configured;\n  } catch (e) {\n    if (e?.code === \"EACCES\" || e?.code === \"EPERM\") {\n      console.warn(`[DATA_DIR] '${configured}' not writable → fallback ~/.${APP_NAME}`);\n      return defaultDir();\n    }\n    throw e;\n  }\n}\n\nconst DATA_DIR = getDataDir();\nconst MITM_DIR = path.join(DATA_DIR, \"mitm\");\n\nmodule.exports = { DATA_DIR, MITM_DIR };\n","sourceCodeStart":4,"sourceCodeEnd":33,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/mitm/paths.js#L4-L33","documentation":"getDataDir() honors a user-configured DATA_DIR env var; if creating that directory fails with EACCES or EPERM, it warns and falls back to the default per-user directory (~/.9router, or %APPDATA%\\9router on Windows). All MITM/state files then live in the fallback location instead of the configured one. Other mkdir errors (e.g. ENOTDIR, invalid path) are re-thrown.","triggerScenarios":"DATA_DIR env is set but mkdirSync(configured, {recursive:true}) fails with EACCES/EPERM: path owned by another user, read-only mount, sandbox/container restrictions, or a protected system path.","commonSituations":"Docker volume mounted read-only; running the app as non-root with DATA_DIR=/etc or /var/9router owned by root; Windows Program Files as target; systemd service with a hardened ProtectHome/ReadOnlyPaths; macOS sandbox denying a custom path.","solutions":["Fix permissions on the configured DATA_DIR: chown/chmod it so the running user can write (sudo chown -R $USER <dir>).","Pick a writable DATA_DIR (e.g. /var/lib/9router with proper ownership, or a user-owned path) and restart.","If the fallback is acceptable, unset DATA_DIR or copy old data from the configured dir into ~/.9router to keep history.","If the error persists as a non-EACCES crash, fix the invalid path value in DATA_DIR (trailing garbage, wrong drive)."],"exampleFix":"// before\nDATA_DIR=/var/lib/9router   # owned by root → EACCES fallback\n// after\nsudo mkdir -p /var/lib/9router && sudo chown $USER /var/lib/9router\nexport DATA_DIR=/var/lib/9router","handlingStrategy":"validation","validationCode":"// validate DATA_DIR before starting the app\nimport fs from \"fs\";\nconst dir = process.env.DATA_DIR;\nif (dir) {\n  try {\n    fs.mkdirSync(dir, { recursive: true });\n    fs.accessSync(dir, fs.constants.W_OK);\n    console.log(\"DATA_DIR OK:\", dir);\n  } catch (e) {\n    console.error(\"DATA_DIR not writable:\", e.code); // expect fallback to ~/.9router\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["chown/chmod the configured DATA_DIR to the user running the app.","Never point DATA_DIR at protected system paths (Program Files, /etc, /usr).","In Docker, mount the data volume read-write, not read-only.","After seeing this warning, remember data went to ~/.9router — migrate old files there if needed."],"tags":["filesystem","permissions","env-var","data-dir","fallback"],"backgroundTag":"directory-not-writable","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}