paperclipai/paperclip · error

Explicit skill inputs are supported only by Codex

Error message

Explicit skill inputs are supported only by Codex

What it means

Capability guard in the runnerd Codex transport's turn-start path: the incoming turn input contains explicit skill inputs (type: 'skill' items), but the active agent is not Codex — explicit skill inputs are a Codex-only feature (they map to files on the Codex filesystem), so the transport rejects the turn instead of silently dropping the skills. Generic validation — the input at fault is skill items in a turn addressed to a non-Codex agent.

Solutions

  1. Route turns carrying explicit skill inputs to a Codex-backed transport.
  2. Strip skill items from the input for non-Codex agents or inline their content as plain text instead.
  3. Gate the caller's skill-input feature on the agent type before submitting the turn.
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:5493 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18). Data as JSON: /api/errors/662c93b83adb0c66. Report an issue: GitHub.

Appendix: source

Thrown at packages/paperclip-runner/src/live/runnerd-codex-transport.ts:5493

    params: Record<string, unknown>,
  ): Promise<Record<string, unknown>> {
    const turnStartTimeoutMs = this.options.turnStartTimeoutMs ?? 30_000;
    if (!Number.isSafeInteger(turnStartTimeoutMs) || turnStartTimeoutMs <= 0) {
      throw new Error("turnStartTimeoutMs must be a positive safe integer");
    }
    const commandDeadline = Date.now() + turnStartTimeoutMs;
    const input = Array.isArray(params.input) ? params.input.map(record) : [];
    const message = input
      .filter((item) => item.type !== "skill")
      .map((item) => (typeof item.text === "string" ? item.text : ""))
      .join("\n");
    const skills = resolveRunnerdCodexSkillInputs(
      input.filter((item) => item.type === "skill"),
      this.options.runtimeContext ?? null,
      resolve(this.options.runnerFilesystemRoot ?? this.#root, "codex-home"),
    );
    if (skills.length && (this.options.provider ?? "codex") !== "codex") {
      throw new Error("Explicit skill inputs are supported only by Codex");
    }
    const pendingTurnId = `turn_lab_${randomUUID().replaceAll("-", "")}`;
    this.#turnId = pendingTurnId;
    const responseEpoch = ++this.#turnStartResponseEpoch;
    this.#turnStartAdmission?.resolve(false);
    let resolveAdmission!: (accepted: boolean) => void;
    this.#turnStartAdmission = {
      settled: new Promise((resolve) => {
        resolveAdmission = resolve;
      }),
      resolve: (accepted) => resolveAdmission(accepted),
    };
    this.#turnStartResponsePending = true;
    let releaseStartResponse!: () => void;
    this.#turnStartResponseSettled = new Promise<void>(resolve => { releaseStartResponse = resolve; });
    this.#expectedProviderTurnId = null;
    let responseReady = false;
    try {

View on GitHub (pinned to 3f1d897a7c)