nanocoai/nanoclaw · warning

Could not read group standing instructions; omitting persona

Error message

Could not read group standing instructions; omitting persona

What it means

Reading the group's standing-instructions (persona) file failed for a reason other than not-existing (ENOENT returns null silently). The persona is omitted from this session's composed context, so the agent behaves less customized until fixed.

Solutions

  1. Check the file path in the log: `ls -la` it and its parents
  2. Replace symlinks with real files (O_NOFOLLOW rejects them by design)
  3. Fix ownership/permissions so the host user can read it

Example fix

# before
ln -s ~/shared/persona.md groups/mygroup/persona.md
# after
cp ~/shared/persona.md groups/mygroup/persona.md
Defensive patterns

Strategy: try-catch

Validate before calling

import fs from 'node:fs';
const st = fs.lstatSync(file);
if (st.isSymbolicLink()) throw new Error('persona must be a real file');

Type guard

function isReadableRegularFile(file: string): boolean {
  try { return fs.lstatSync(file).isFile(); } catch { return false; }
}

Try / catch

try { return readPersona(file); } catch (err) { if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null; log.warn(...); return null; }

Prevention

When it happens

Trigger: openSync with O_NOFOLLOW fails on a symlink (ELOOP), a permission error, or the path is a directory. The O_NOFOLLOW guard makes symlinked persona files fail deliberately.

Common situations: Group folder is a symlink (migration moved it), perms changed, or someone replaced the file with a symlink for editing convenience.

Related errors


AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28). Data as JSON: /api/errors/7ce147c8ddc02499. Report an issue: GitHub.

Appendix: source

Thrown at src/group-persona.ts:38

    return true;
  } catch (err) {
    if (typeof err === 'object' && err !== null && 'code' in err && err.code === 'EEXIST') return false;
    throw err;
  }
}

/** Read a group's standing instructions without following symlinks. */
export function readGroupPersona(groupDir: string): string | null {
  const file = path.join(groupDir, PERSONA_PREPEND_FILE);
  let fd: number | undefined;
  try {
    fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
    if (!fs.fstatSync(fd).isFile()) return null;
    const content = fs.readFileSync(fd, 'utf-8').trim();
    return content || null;
  } catch (err) {
    if (typeof err === 'object' && err !== null && 'code' in err && err.code === 'ENOENT') return null;
    log.warn('Could not read group standing instructions; omitting persona', {
      file,
      error: err instanceof Error ? err.message : String(err),
    });
    return null;
  } finally {
    if (fd !== undefined) fs.closeSync(fd);
  }
}

View on GitHub (pinned to 294ef2aee8)