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

  1. Place the runtime-context entry inside bundleRoot (or copy it in) and reference it relatively
  2. Check with path.relative before calling: ensure the result does not start with '..' and is not absolute
  3. Fix packaging so the entry ships inside the bundle (update build/pack config)
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/9692b88e764364dc. Report an issue: GitHub.