paperclipai/paperclip · error

opencode_run_attach_invalid

opencode_run_attach_invalid

Error message

opencode_run_attach_invalid

What it means

After the busy check, attachRun validates that input.runId is non-empty; an empty string, null, or undefined throws opencode_run_attach_invalid because the driver cannot bind result tracking without a run identifier.

Source

Thrown at packages/paperclip-runner/src/drivers/opencode/opencode-server-driver.ts:509

          opencodeVersion: input.runtime.version,
        },
      },
      { itemId: `${input.providerSessionId}:model` },
    );
  }

  ids() {
    return {
      driverSessionId: this.#providerSessionId,
      providerSessionId: this.#providerSessionId,
      displayId: this.#providerSessionId,
    };
  }

  attachRun(input: { runId: string }): void {
    if (this.#activeTurnId !== null)
      throw new Error("opencode_run_attach_busy");
    if (!input.runId) throw new Error("opencode_run_attach_invalid");
    this.#runId = input.runId;
    this.#result = null;
    this.#resultFingerprint = null;
    this.#resultCallId = null;
    this.#resultTurnId = null;
    this.#semanticResultTextBoundary = null;
    this.#semanticResultProviderMessageId = null;
    this.#lastNonTerminalToolSourceSeq = 0;
    this.#completedTextPartIds.clear();
    this.#completedReasoningPartIds.clear();
    this.#completedTextParts.length = 0;
    this.#terminalTurns.clear();
    this.#sendFullContext = false;
    this.#emit("run.attached", { runId: input.runId, sameSession: true });
  }

  events(): AsyncIterable<PrpEvent> {
    return this.#events;

View on GitHub (pinned to 01ad858492)

Solutions

  1. Create/resolve the run id before attachRun and assert it's a non-empty string at the call site.
  2. Check upstream code that constructs the run record — ensure the id is generated and returned.
  3. Validate run payloads at the boundary (schema/zod) so missing ids fail earlier with a clear message.
  4. Pass a deterministic id (e.g. uuid) if the caller legitimately has no persistence-backed id yet.

Example fix

// before
driver.attachRun({ runId: run?.id ?? '' }); // silently empty -> throws
// after
if (!run?.id) throw new Error(`run record missing id: ${JSON.stringify(run)}`);
driver.attachRun({ runId: run.id });
Defensive patterns

Strategy: validation

Validate before calling

const assertRunId = (id: string | undefined): string => { if (typeof id !== 'string' || id.length === 0) throw new Error('attachRun requires a non-empty runId'); return id; };

Type guard

const isRunId = (v: unknown): v is string => typeof v === 'string' && v.length > 0;

Try / catch

try { driver.attachRun({ runId }); } catch (e) { if ((e as Error).message === 'opencode_run_attach_invalid') { console.error('runId was empty; run record likely unpersisted', { runId }); throw new Error('Create and persist the run record before attaching', { cause: e }); } throw e; }

Prevention

When it happens

Trigger: Calling attachRun({ runId: '' }) or with runId omitted — usually a runner bug where the run record wasn't created/persisted before attaching, or an id field read from an API response that was undefined.

Common situations: Database row not yet assigned an id, destructuring a missing field from a run payload, template string defaults collapsing to empty string, migration gaps leaving runs without identifiers.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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