paperclipai/paperclip · error
native_runtime_context_entry_outside_bundle
native_runtime_context_entry_outside_bundle
Error message
native_runtime_context_entry_outside_bundle
What it means
nativeSystemInstructions reads a runtime-context entry file and computes its path relative to the bundle root to compose native system instructions. If the entry path resolves outside the bundle root (relative path starts with '../', equals '..', or is absolute), it throws native_runtime_context_entry_outside_bundle to block reads outside the shipped bundle. This is a path-containment guard, not a validation of file content.
Source
Thrown at packages/paperclip-runner/src/backends/runtime-context.ts:22
import type { NativeExecutionInput } from "../contracts/native-execution.js";
import { composeNativeSystemInstructions } from "../contracts/runtime-context.js";
export function nativeSystemInstructions(input: NativeExecutionInput): string {
if (!("runtimeContext" in input)) return CODEX_SKILLLESS_BASE_INSTRUCTIONS;
const configuredRoot = resolve(
input.runtimeContext.instructions.bundle.rootPath,
);
const bundleRoot = realpathSync(configuredRoot);
const entryPath = realpathSync(
resolve(configuredRoot, input.runtimeContext.instructions.entryPath),
);
const pathFromRoot = relative(bundleRoot, entryPath);
if (
pathFromRoot === ".." ||
pathFromRoot.startsWith(`..${sep}`) ||
isAbsolute(pathFromRoot)
) {
throw new Error("native_runtime_context_entry_outside_bundle");
}
const entry = readFileSync(entryPath, "utf8");
return composeNativeSystemInstructions(input.runtimeContext, entry);
}
export function nativeTaskConstraints(input: NativeExecutionInput): string[] {
const finalResponseConstraint =
"Invoke paperclip_finish or paperclip_block exactly once before writing the complete user-facing final response. Use paperclip_finish with yielded and a response_wake continuation only when explicitly waiting for the next response. After the semantic tool succeeds, write that response exactly once and do not call another tool.";
const answeredQuestions = Array.isArray(input.interactionResponses)
? input.interactionResponses.flatMap((response, responseIndex) => {
if (
response.kind !== "ask_user_questions" ||
response.response?.status !== "answered" ||
typeof response.interactionId !== "string" ||
response.interactionId.trim().length === 0
) {
return [];
}View on GitHub (pinned to 01ad858492)
Solutions
- Place the runtime-context entry inside bundleRoot (or copy it in) and reference it relatively
- Check with path.relative before calling: ensure the result does not start with '..' and is not absolute
- Fix packaging so the entry ships inside the bundle (update build/pack config)
- Resolve symlinks (fs.realpathSync) and verify containment before invoking
Example fix
// before
await nativeSystemInstructions({ runtimeContext: { entryPath: '/etc/agent/context.md', ... } });
// after
const rel = path.relative(bundleRoot, entryPath);
if (rel.startsWith('..') || path.isAbsolute(rel)) {
entryPath = path.join(bundleRoot, 'runtime-context', 'context.md'); // copy asset into bundle
}
await nativeSystemInstructions({ runtimeContext: { entryPath, ... } }); Defensive patterns
Strategy: validation
Validate before calling
const rel = path.relative(bundleRoot, entryPath);
if (rel === '..' || rel.startsWith('..' + path.sep) || path.isAbsolute(rel)) throw new Error('entry outside bundle'); Type guard
function isInsideBundle(bundleRoot: string, entryPath: string): boolean {
const rel = path.relative(bundleRoot, path.resolve(entryPath));
return rel !== '..' && !rel.startsWith('..' + path.sep) && !path.isAbsolute(rel);
} Try / catch
try { return nativeSystemInstructions(input); } catch (e) { if (e.message === 'native_runtime_context_entry_outside_bundle') { return composeWithBundledFallback(input); } throw e; } Prevention
- Ship runtime-context entries inside the bundle at build time
- Reject user-supplied entry paths containing '..' or absolute paths
- Resolve symlinks and re-check containment before use
- Test in packaged (not just dev) layouts
When it happens
Trigger: input.runtimeContext entryPath pointing at a file outside bundleRoot: an absolute path, a path with ../ traversal, or a symlink-resolved location outside the bundle.
Common situations: Configuring a custom runtime-context entry in a repo checkout instead of the bundled install; dev vs packaged layout mismatch where the entry resolves differently; symlinked node_modules or monorepo workspaces making the relative path cross the bundle boundary; user-supplied path containing '..'.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- Trusted viewer must not use symlinks
- ACPX snapshot escaped its package
- Invalid canonical workspace path
- Access denied
- UI parser path escapes package directory — skipping
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/9692b88e764364dc.
Report an issue: GitHub.