{"record":{"id":"7ce147c8ddc02499","repo":"nanocoai/nanoclaw","slug":"could-not-read-group-standing-instructions-omitti","errorCode":null,"errorMessage":"Could not read group standing instructions; omitting persona","messagePattern":"Could not read group standing instructions; omitting persona","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/group-persona.ts","lineNumber":38,"sourceCode":"    return true;\n  } catch (err) {\n    if (typeof err === 'object' && err !== null && 'code' in err && err.code === 'EEXIST') return false;\n    throw err;\n  }\n}\n\n/** Read a group's standing instructions without following symlinks. */\nexport function readGroupPersona(groupDir: string): string | null {\n  const file = path.join(groupDir, PERSONA_PREPEND_FILE);\n  let fd: number | undefined;\n  try {\n    fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);\n    if (!fs.fstatSync(fd).isFile()) return null;\n    const content = fs.readFileSync(fd, 'utf-8').trim();\n    return content || null;\n  } catch (err) {\n    if (typeof err === 'object' && err !== null && 'code' in err && err.code === 'ENOENT') return null;\n    log.warn('Could not read group standing instructions; omitting persona', {\n      file,\n      error: err instanceof Error ? err.message : String(err),\n    });\n    return null;\n  } finally {\n    if (fd !== undefined) fs.closeSync(fd);\n  }\n}\n","sourceCodeStart":20,"sourceCodeEnd":47,"githubUrl":"https://github.com/nanocoai/nanoclaw/blob/294ef2aee85218b23ad30eda9dfe10e590b54a8c/src/group-persona.ts#L20-L47","documentation":"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.","triggerScenarios":"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.","commonSituations":"Group folder is a symlink (migration moved it), perms changed, or someone replaced the file with a symlink for editing convenience.","solutions":["Check the file path in the log: `ls -la` it and its parents","Replace symlinks with real files (O_NOFOLLOW rejects them by design)","Fix ownership/permissions so the host user can read it"],"exampleFix":"# before\nln -s ~/shared/persona.md groups/mygroup/persona.md\n# after\ncp ~/shared/persona.md groups/mygroup/persona.md","handlingStrategy":"try-catch","validationCode":"import fs from 'node:fs';\nconst st = fs.lstatSync(file);\nif (st.isSymbolicLink()) throw new Error('persona must be a real file');","typeGuard":"function isReadableRegularFile(file: string): boolean {\n  try { return fs.lstatSync(file).isFile(); } catch { return false; }\n}","tryCatchPattern":"try { return readPersona(file); } catch (err) { if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null; log.warn(...); return null; }","preventionTips":["Never symlink persona/CLAUDE files — copy instead","Keep group folders owned by the host user","Check the file after group-folder migrations"],"tags":["persona","filesystem","symlink","group-config"],"backgroundTag":"file-read-permission-denied","analyzedSha":"294ef2aee85218b23ad30eda9dfe10e590b54a8c","analyzedAt":"2026-08-28T13:59:10.357Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}