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
- 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.
- Update the connection's local stdio config to point credential configPath at a secret that actually exists on this host.
- Inspect the connection health status (markRemoteConnectionHealth set it to 'missing_secret') and re-test the connection after fixing the credential.
- 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
- Add a startup health check that resolves every local stdio connection's credentials and flags 'missing_secret' before agents run.
- Provision secrets on new hosts/CI runners as part of environment setup (documented .env or secret-store bootstrap).
- When rotating credentials, update both the store and any connection configPaths that reference them.
- Treat connection health status 'missing_secret' as blocking and surface it before scheduling agent work.
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
- database-contract-unmet
- Invalid public base URL
- mcp_transport_unsupported
- organization_authorization_required
- PAPERCLIP_OPENCODE_RUNTIME_DIR is required
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)