{"record":{"id":"38af71133f796e4c","repo":"paperclipai/paperclip","slug":"refusing-to-modify-non-regular-shell-rc-file-rcp","errorCode":null,"errorMessage":"Refusing to modify non-regular shell rc file ${rcPath}.","messagePattern":"Refusing to modify non-regular shell rc file (.+?)\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"cli/src/install-store.ts","lineNumber":428,"sourceCode":"    fs.rmSync(paths.shimPath, { force: true });\n    return true;\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return true;\n    throw error;\n  }\n}\n\nexport function managedPathBlock(): string {\n  return `${PATH_BLOCK_START}\\nexport PATH=\"$HOME/.local/bin:$PATH\"\\n${PATH_BLOCK_END}`;\n}\n\nexport function addManagedPathBlock(rcPath: string): boolean {\n  let existing = \"\";\n  let mode = 0o600;\n  try {\n    const stat = fs.lstatSync(rcPath);\n    if (!stat.isFile() || stat.isSymbolicLink()) {\n      throw new Error(`Refusing to modify non-regular shell rc file ${rcPath}.`);\n    }\n    assertOwnedByCurrentUser(stat, rcPath);\n    mode = stat.mode & 0o777;\n    existing = fs.readFileSync(rcPath, \"utf8\");\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n  }\n  if (existing.includes(PATH_BLOCK_START)) return false;\n  fs.mkdirSync(path.dirname(rcPath), { recursive: true });\n  const prefix = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n  writeFileAtomic(rcPath, `${existing}${prefix}${managedPathBlock()}\\n`, mode);\n  return true;\n}\n\nexport function removeManagedPathBlock(rcPath: string): boolean {\n  let existing: string;\n  let mode: number;\n  try {","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/cli/src/install-store.ts#L410-L446","documentation":"Thrown by addManagedPathBlock when the target shell rc file (e.g., ~/.bashrc, ~/.zshrc) exists but is not a regular file or is a symbolic link. Before appending the managed PATH export block, the installer verifies the rc file is a plain, user-owned file to prevent writing through symlinks or to special files, which could corrupt user environments or write to unintended locations.","triggerScenarios":"Calling addManagedPathBlock(rcPath) where rcPath exists but is a symlink, directory, socket, or other non-regular file. This typically happens during 'paperclipai install' when it tries to add the PATH block to shell rc files.","commonSituations":"A dotfile manager (e.g., stow, chezmoi) symlinks ~/.bashrc to a managed source file. The rc file is symlinked to a shared/network location. A user accidentally created ~/.bashrc as a directory.","solutions":["Inspect the rc file: 'ls -la ~/.bashrc' (or the relevant rc path) to confirm its type.","If it is a symlink to a real config file, resolve the target and either point the installer at the real file or replace the symlink with a regular file.","If using a dotfile manager, add the PATH export block manually to the managed source file.","Alternatively, set the PATH manually: 'export PATH=\"$HOME/.local/bin:$PATH\"' in your shell config."],"exampleFix":"// before: ~/.bashrc is a symlink managed by chezmoi\n// ls -la ~/.bashrc -> lrwxrwxrwx -> ~/.local/share/chezmoi/dot_bashrc\n\n// after: add the PATH block to the real source file instead\n// echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.local/share/chezmoi/dot_bashrc\n// chezmoi apply","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\n\nfunction isSafeRcFile(rcPath: string): boolean {\n  try {\n    const stat = fs.lstatSync(rcPath);\n    return stat.isFile() && !stat.isSymbolicLink();\n  } catch (error) {\n    return (error as NodeJS.ErrnoException).code === 'ENOENT';\n  }\n}\n\n// Call before addManagedPathBlock:\nif (!isSafeRcFile(rcPath)) {\n  console.warn(`Shell rc file ${rcPath} is a symlink or non-regular file; skipping PATH block.`);\n  // Manually add: export PATH=\"$HOME/.local/bin:$PATH\"\n}","typeGuard":null,"tryCatchPattern":"try {\n  addManagedPathBlock(rcPath);\n} catch (error) {\n  if (error instanceof Error && error.message.includes('non-regular shell rc file')) {\n    // rc file is symlinked (e.g., dotfile manager); add PATH manually to the source\n    console.warn(`Add manually: export PATH=\\\"$HOME/.local/bin:$PATH\\\" to ${rcPath}'s real target`);\n  } else {\n    throw error;\n  }\n}","preventionTips":["If using a dotfile manager (chezmoi, stow, etc.), add the PATH export to the managed source file, not the symlink.","Resolve symlinked rc files to their real path before calling addManagedPathBlock.","You can always add 'export PATH=\"$HOME/.local/bin:$PATH\"' manually to skip the automated rc modification."],"tags":["security","shell-rc","install-store","cli"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}