invalidapikey
The request carried an API key, but the API does not recognize it. The key may be mistyped, cut short, padded with a hidden character, or from another account. Retrying sends the same key and gets the same answer. This page is part of the error code reference.
| HTTP status | 401 Unauthorized |
error.type |
authentication_error |
error.retryable |
false |
| Credits used | 0 |
Example response
{ "error": { "type": "authentication_error", "code": "invalid_api_key", "message": "API key not recognized", "retryable": false, "docs": "https://docs.renderscreenshot.com/errors/invalid_api_key" }, "request_id": "req_abc123" }
Related 401 codes: missing_credentials means the API found no usable key in the request at all, and revoked_key means the key existed but was revoked. A malformed Authorization header can be reported as missing_credentials rather than invalid_api_key, so handle every 401 the same way.
Common causes
- Hidden characters. A trailing newline or
\rfrom a secrets file, a Windows.envfile, orechowithout-n. The key looks right when printed but does not match. - A cut-off or wrapped key. Copied from a terminal or a chat message that broke the line.
- The wrong key type. API requests with a Bearer header take an
rs_live_key.rs_pub_andrs_secret_keys are for signed URLs. - A stale environment. The key was rotated, but a container, CI secret or serverless function still has the old value until it redeploys.
- The header format. It must be
Authorization: Bearer rs_live_...with exactly one space.Bearer Bearer ...or a key in quotes fails. See Bearer token authentication.
How to fix it
- Check the shape of the key in the same environment as the failing process (container, CI job, server), not on your laptop:
# Is the variable set, and does it have the documented shape? if [[ "$RS_API_KEY" =~ ^rs_live_[A-Za-z0-9]{32}$ ]]; then echo "key shape OK" else echo "key shape wrong: length ${#RS_API_KEY}, starts with '${RS_API_KEY:0:8}'" printf '%s' "$RS_API_KEY" | od -c | tail -n 3 # shows hidden \n, \r or spaces fi
- Call an endpoint that only needs a key, such as
GET /v1/usage:
curl -s https://api.renderscreenshot.com/v1/usage -H "Authorization: Bearer $RS_API_KEY"
- If the key is wrong or lost, create a new one in the dashboard under API Keys. The full key is shown only once, so store it straight into your secret manager. See API keys.
- Deploy the new key everywhere, then revoke the old one.
Fail fast at startup
A worker with a bad key fails every job, and a retry loop can hide that for hours. Check the key once at boot and stop the process if it is rejected. The script never prints the full key.
// key-preflight.mjs (Node 22+): run once at boot, before any worker starts. const API = process.env.RS_BASE_URL ?? 'https://api.renderscreenshot.com'; const key = (process.env.RS_API_KEY ?? '').trim(); if (!key) { console.error('RS_API_KEY is empty. Set it in the environment of this process.'); process.exit(1); } const res = await fetch(`${API}/v1/usage`, { headers: { Authorization: `Bearer ${key}` } }); if (res.status === 401) { const { error, request_id } = await res.json(); // Show only the prefix and the last 4 characters, never the full key. console.error(`Key ${key.slice(0, 8)}...${key.slice(-4)} rejected: ${error.code} (${request_id})`); process.exit(1); } if (!res.ok) throw new Error(`Preflight failed with HTTP ${res.status}`); const usage = await res.json(); console.log(`API key OK, ${usage.credits.remaining} credits left this period`);
The script trims whitespace. If you trim here, pass the same trimmed value to the rest of your app, or fix the secret at the source.
In code that uses the Node SDK, every 401 is a configuration error, so stop instead of retrying:
import { Client, TakeOptions, RenderScreenshotError } from 'renderscreenshot'; const client = new Client(process.env.RS_API_KEY); try { await client.take(TakeOptions.url('https://example.com')); } catch (error) { if (error instanceof RenderScreenshotError && error.httpStatus === 401) { // Every 401 is a configuration problem. Stop the worker and alert a person. console.error('RenderScreenshot rejected the API key. Check RS_API_KEY.'); process.exit(1); } throw error; }
Tested on 2026-10-15 with bash and zsh, Node 22.18 and renderscreenshot 1.1.0 for Node, against a local mock. The shape check flagged a key with a trailing \r (length 41); the preflight passed a good key, rejected an unknown key with exit code 1, and stopped on an empty variable.
Related
- API keys for key types and rotation.
- Error handling and retries for why 4xx errors other than 422 and 429 are never retried.