nexu-io/open-design · critical · Error

OD_DATA_DIR "${resolved}" is not writable: ${e.message} Curr

Error message

OD_DATA_DIR "${resolved}" is not writable: ${e.message} Current user: ${currentUser} Check whether the folder or one of its parents is owned by another user, is a symlink to a protected location, or was previously created with sudo. Try: ls -ld "${parentDir}" "${resolved}" If the folder should belong to you, fix ownership/permissions, for example: sudo chown -R "${currentUser}":staff "${parentDir}" && chmod -R u+rwX "${parentDir}"

What it means

Thrown by resolveDataDir() when the resolved OD_DATA_DIR cannot be created (mkdirSync recursive) or is not writable (accessSync W_OK). The message is intentionally verbose: it includes the underlying fs error, the current OS user, the parent dir, and concrete remediation commands (ls -ld, chown, chmod). It exists so permission/symlink/sudo-ownership problems surface with actionable diagnostics rather than a cryptic EACCES.

Source

Thrown at apps/daemon/src/daemon-paths.ts:152

    }
    return path.join(projectRoot, '.od');
  }

  const resolved = resolveProjectRelativePath(value, projectRoot);
  try {
    fs.mkdirSync(resolved, { recursive: true });
    fs.accessSync(resolved, fs.constants.W_OK);
  } catch (err) {
    const e = err as Error;
    const currentUser = (() => {
      try {
        return os.userInfo().username;
      } catch {
        return process.env.USER ?? process.env.LOGNAME ?? 'unknown';
      }
    })();
    const parentDir = path.dirname(resolved);
    throw new Error(
      [
        `OD_DATA_DIR "${resolved}" is not writable: ${e.message}`,
        `Current user: ${currentUser}`,
        'Check whether the folder or one of its parents is owned by another user, is a symlink to a protected location, or was previously created with sudo.',
        `Try: ls -ld "${parentDir}" "${resolved}"`,
        `If the folder should belong to you, fix ownership/permissions, for example: sudo chown -R "${currentUser}":staff "${parentDir}" && chmod -R u+rwX "${parentDir}"`,
      ].join(' '),
    );
  }
  return resolved;
}

View on GitHub (pinned to 5be4028344)

Solutions

  1. Run the chown/chmod command suggested in the error message for the parent dir and target (e.g. sudo chown -R $USER:staff <parent> && chmod -R u+rwX <parent>).
  2. Point OD_DATA_DIR at a directory the current user owns and that is not a symlink to a protected location.
  3. If the dir is on a mounted volume, remount it read-write or pick a writable mount.

Example fix

# before: dir left root-owned by a prior sudo run
ls -ld /var/lib/open-design   # owner: root

# after: fix ownership, then restart the daemon
sudo chown -R $(whoami):staff /var/lib/open-design
chmod -R u+rwX /var/lib/open-design
Defensive patterns

Strategy: validation

Validate before calling

import fs from 'node:fs';
const target = resolveProjectRelativePath(process.env.OD_DATA_DIR!, projectRoot);
fs.mkdirSync(target, { recursive: true });
try { fs.accessSync(target, fs.constants.W_OK); }
catch { throw new Error(`OD_DATA_DIR ${target} not writable by ${os.userInfo().username}`); }

Type guard

function isWritable(p: string): boolean {
  try { fs.accessSync(p, fs.constants.W_OK); return true; } catch { return false; }
}

Try / catch

try { resolveDataDir(process.env.OD_DATA_DIR, projectRoot); }
catch (e) {
  if (e instanceof Error && /not writable/.test(e.message)) {
    // surface the embedded chown/chmod hint; do not auto-fix permissions
  } else throw e;
}

Prevention

When it happens

Trigger: OD_DATA_DIR points at a directory owned by another user (commonly root, after a sudo run), a read-only mount, a symlink to a protected location, or a path whose parent lacks write permission.

Common situations: User previously ran the daemon with sudo, leaving dirs root-owned; OD_DATA_DIR on a read-only filesystem or a Docker volume mounted read-only; a symlink chain lands in /usr/local or another system path; SELinux/AppArmor denies writes despite Unix perms looking fine.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/91e2f610da94e283. Report an issue: GitHub.