nanocoai/nanoclaw · warning
Shared skill not symlinked: real entry occupies the path (te
Error message
Shared skill not symlinked: real entry occupies the path (template overlay or stale pre-refactor copy)
What it means
While syncing shared skills as symlinks into a group's skills directory, an existing real (non-symlink) entry occupies the path. This is either an intentional template overlay or a stale pre-refactor copy shadowing the shared skill (#3001); since no marker distinguishes them, the shared skill is skipped with a warning.
Source
Thrown at src/container-runner.ts:831
}
// Create symlinks for desired skills (container path targets)
for (const skill of desired) {
const linkPath = path.join(skillsDir, skill);
let entry: fs.Stats | undefined;
try {
entry = fs.lstatSync(linkPath);
} catch {
/* missing */
}
if (!entry) {
fs.symlinkSync(`/app/skills/${skill}`, linkPath);
} else if (!entry.isSymbolicLink()) {
// A real entry here is either a template overlay (intentional; see
// src/group-skills.ts) or a stale pre-refactor skill copy that shadows
// the shared skill (#3001). No marker distinguishes them yet, so
// surface the skip instead of staying silent.
log.warn(
'Shared skill not symlinked: real entry occupies the path (template overlay or stale pre-refactor copy)',
{
skill,
path: linkPath,
},
);
}
}
}
/**
* Resolve the group's skill selection to concrete names — `'all'` recomputes
* from `container/skills/` so newly-added upstream skills appear automatically.
*/
function selectedSkillNames(containerConfig: import('./container-config.js').ContainerConfig): string[] {
if (containerConfig.skills !== 'all') return containerConfig.skills;
const sharedSkillsDir = path.join(process.cwd(), 'container', 'skills');
return fs.existsSync(sharedSkillsDir)View on GitHub (pinned to 294ef2aee8)
Solutions
- If the local copy is stale (pre-refactor), delete it: `rm -rf groups/<folder>/skills/<skill>` so the symlink is created
- If it's an intentional template overlay, verify the local copy is current and ignore the warning
- Diff the local copy against `container/skills/<skill>` to decide which case it is
Example fix
rm -rf groups/my-group/skills/agent-browser # stale copy; next spawn symlinks the shared skill
Defensive patterns
Strategy: validation
Validate before calling
const entry = fs.lstatSync(linkPath, { throwIfNoEntry: false });
if (entry && !entry.isSymbolicLink()) {
// decide: template overlay (keep) vs stale copy (delete) before spawning
} Type guard
function isStaleSkillCopy(p: string): boolean {
return fs.lstatSync(p).isSymbolicLink() === false && !isTemplateOverlay(p);
} Prevention
- Keep group skills dirs clean after refactors; remove duplicated shared skills
- Document which skills a template overlays
- After group template changes, diff groups/<folder>/skills against container/skills
When it happens
Trigger: `syncSkillSymlinks` (called from `buildMounts`) finds a real file/directory at `groups/<folder>/skills/<skill>` where a symlink to `/app/skills/<skill>` should go.
Common situations: A group created from a template that ships its own version of a shared skill; leftover skill copies from before the shared-mount refactor blocking updates to that skill.
Related errors
- engage_mode '${w.engage_mode}' can never engage on channel '
- chat-sdk bridge instance ${JSON.stringify(config.instance)}
- ${NANOCLAW_EXTENSION_NS}/context/instructions.md must be a r
- Plugin rejected: "${rel}" is not a regular file or directory
- Could not read group standing instructions; omitting persona
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/0959dcba373f90df.
Report an issue: GitHub.