paperclipai/paperclip · error · Error
Systemd service values must not contain line breaks
Error message
Systemd service values must not contain line breaks
What it means
Thrown by escapeSystemd when a value being interpolated into a systemd unit file contains a carriage return (\r) or newline (\n). Systemd unit files are line-oriented; inserting a newline into a value field could inject additional directives (e.g., a value containing '\nExecStart=malicious-command'). This is a fail-closed injection-prevention guard applied before any escaping occurs.
Source
Thrown at cli/src/services/service-manager.ts:57
export type CommandResult = { stdout: string; stderr: string };
export type CommandRunner = (command: string, args: string[], options?: { inherit?: boolean }) => Promise<CommandResult>;
export const defaultCommandRunner: CommandRunner = async (command, args, options) => {
if (options?.inherit) {
await new Promise<void>((resolve, reject) => {
const child = execFile(command, args, { windowsHide: true }, (error) => error ? reject(error) : resolve());
child.stdout?.pipe(process.stdout);
child.stderr?.pipe(process.stderr);
});
return { stdout: "", stderr: "" };
}
const result = await execFileAsync(command, args, { encoding: "utf8", windowsHide: true });
return { stdout: result.stdout, stderr: result.stderr };
};
function escapeSystemd(value: string): string {
if (/\r|\n/.test(value)) {
throw new Error("Systemd service values must not contain line breaks");
}
return value
.replaceAll("\\", "\\\\")
.replaceAll('"', '\\"')
.replaceAll("$", () => "$$")
.replaceAll("%", "%%");
}
function escapeXml(value: string): string {
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
}
function escapeRegExp(value: string): string {
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
export function resolveServiceShimPath(homeDir = os.homedir()): string {
return process.env.PAPERCLIP_SHIM_PATH?.trim() || path.join(homeDir, ".local", "bin", "paperclipai");View on GitHub (pinned to 67001ec6eb)
Solutions
- Check the environment variables: 'echo "$PAPERCLIP_INSTANCE_ID" | cat -v' to reveal hidden characters.
- Strip newlines from the instance ID before passing it: ensure the --instance flag value has no line breaks.
- If PAPERCLIP_HOME or the shim path contains newlines, fix the environment to use clean single-line paths.
- Use a simple alphanumeric instance ID: instance IDs should match the expected identifier format.
Example fix
// before: instance ID contains a trailing newline // PAPERCLIP_INSTANCE_ID='default\n' // after: clean instance ID // PAPERCLIP_INSTANCE_ID='default' // or sanitize before use: const cleanInstanceId = instanceId.replace(/[\r\n]/g, '');
Defensive patterns
Strategy: validation
Validate before calling
function isSafeSystemdValue(value: string): boolean {
return !/\r|\n/.test(value);
}
// Call before renderSystemdUnit / SystemdServiceManager construction:
const fields = [instanceId, shimPath, homeDir];
for (const field of fields) {
if (!isSafeSystemdValue(field)) {
throw new Error(`Field contains line breaks and cannot be used in a systemd unit: ${JSON.stringify(field)}`);
}
} Try / catch
try {
const unit = renderSystemdUnit({ instanceId, shimPath, homeDir });
} catch (error) {
if (error instanceof Error && error.message === 'Systemd service values must not contain line breaks') {
// Sanitize the offending field
const cleanInstanceId = instanceId.replace(/[\r\n]/g, '');
// Retry with cleaned values
}
throw error;
} Prevention
- Ensure PAPERCLIP_INSTANCE_ID, PAPERCLIP_HOME, and shim paths are single-line values with no trailing newlines.
- In CI/CD pipelines, use 'echo -n' or .strip() when setting environment variables to avoid trailing newlines.
- Validate user-supplied instance IDs against a safe charset (e.g., /^[A-Za-z0-9._-]+$/) before using them in service definitions.
When it happens
Trigger: Calling renderSystemdUnit or any code path that calls escapeSystemd with an instanceId, shimPath, or homeDir that contains a newline or carriage return character. This includes the SystemdServiceManager constructor and its renderDefinition/install/start/restart methods.
Common situations: PAPERCLIP_INSTANCE_ID is set to a value containing a newline (e.g., from a misconfigured CI variable or a copy-paste with trailing newline). PAPERCLIP_HOME or PAPERCLIP_SHIM_PATH contains a newline. An attacker or broken script passes a crafted instance ID.
Related errors
- Refusing to write service definition through unsafe director
- Refusing to write service definition in directory not owned
- Refusing to replace unsafe service definition ${filePath}.
- Refusing to write export file outside output directory: ${re
- Refusing to use non-directory install-store path ${directory
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/7b9599699cf3a426.
Report an issue: GitHub.