paperclipai/paperclip · error · ToolGatewayHttpError

local_stdio_missing_secret

local_stdio_missing_secret

Error message

A configured local stdio credential could not be resolved.

What it means

This ToolGatewayHttpError (HTTP 422) is thrown when a local stdio MCP connection references a credential (grantRef.configPath) that cannot be resolved from the local environment/secrets store; the resolution attempt threw and the catch block first marks the connection health as 'missing_secret', then throws. The connection is unusable until the referenced secret exists where the server can read it.

Solutions

  1. Create/restore the missing secret at the referenced location so grantRef.configPath resolves (set the env var or add the entry to the local secrets store), then retry.
  2. Update the connection's local stdio config to point credential configPath at a secret that actually exists on this host.
  3. Inspect the connection health status (markRemoteConnectionHealth set it to 'missing_secret') and re-test the connection after fixing the credential.
  4. If the credential was rotated, re-authorize or re-create the connection so its credential references match the current store keys.

Example fix

// before: connection config references a secret that is absent
{ "transport": "local_stdio", "credential": { "configPath": "env.GITHUB_TOKEN" } } // GITHUB_TOKEN unset
// after: provide it where the server runs
export GITHUB_TOKEN=$(op read "op://Vault/github/token") # or add to the server's .env
Defensive patterns

Strategy: validation

Validate before calling

const secret = process.env[grantRef.configPath.replace(/^env\./, "")];
if (!secret || secret.trim() === "") {
  throw new Error(`Local stdio credential ${grantRef.configPath} is not set for connection ${connection.id}.`);
}

Type guard

function hasResolvableCredential(grantRef: { configPath: string }, env: Record<string, string | undefined>): boolean {
  const key = grantRef.configPath.startsWith("env.") ? grantRef.configPath.slice(4) : grantRef.configPath;
  return Boolean(env[key] && env[key]!.length > 0);
}

Try / catch

try {
  await callLocalStdioTool(session, connectionId, toolName, args);
} catch (e) {
  if (e instanceof ToolGatewayHttpError && e.code === "local_stdio_missing_secret") {
    return { status: "missing_secret", credential: e.details.credential, remediation: `Set ${e.details.credential} on the server host` };
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a tool through a connection with transport 'local_stdio' whose runtime template includes a credential reference (configPath) that fails resolution — e.g. the referenced env secret is absent, the secrets store entry was deleted, or the credential file/key is unreadable so the resolve call throws.

Common situations: Running the server on a new machine or CI runner where the .env / secret file backing the stdio credential was never copied; rotating credentials in the secrets store without updating the connection config; a typo'd or stale configPath after a migration; exported connection configs referencing machine-local secrets that don't exist elsewhere.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at server/src/services/tool-gateway.ts:4862

    for (const key of template.envKeys) {
      const grantRef = grant.credentialSecretRefs.find(
        (ref) => ref.configPath === `env.${key}`,
      );
      if (!grantRef) continue;
      try {
        env[key] = await resolveGrantSecretValue(
          session,
          connection,
          grant,
          grantRef,
        );
      } catch {
        await markRemoteConnectionHealth(
          connection,
          "missing_secret",
          "A configured local stdio credential could not be resolved.",
        );
        throw new ToolGatewayHttpError(
          422,
          "A configured local stdio credential could not be resolved.",
          "local_stdio_missing_secret",
          { connectionId: connection.id, credential: grantRef.configPath },
        );
      }
    }
    return env;
  }

  function stdioProtocolError(
    message: string,
    details: Record<string, unknown> = {},
  ) {
    return new ToolGatewayHttpError(
      502,
      message,
      "local_stdio_protocol_error",

View on GitHub (pinned to 3f1d897a7c)