How to Fix ERROR_KEY_DOES_NOT_EXIST and Wrong User Key

error_key_does_not_exist - How to Fix ERROR_KEY_DOES_NOT_EXIST and Wrong User Key

Short answer: ERROR_KEY_DOES_NOT_EXIST means the API key in your request is not a key the solver recognises. Nothing is wrong with the CAPTCHA, the sitekey or the page URL. The request never got as far as being solved. This guide covers the three things that actually cause it, the fix in all four SDKs, and why you sometimes get ERROR_WRONG_USER_KEY instead.

What ERROR_KEY_DOES_NOT_EXIST means

It comes back from /in.php, at submit time, before any solving starts. The API compared the key parameter in your request against the key it is configured to accept, and did not find a match.

# Submitting with a key the app does not know:
curl "http://127.0.0.1:8080/in.php?key=WRONG&method=userrecaptcha&googlekey=YOUR_SITEKEY&pageurl=https://example.com"

ERROR_KEY_DOES_NOT_EXIST

Because it is returned at submit time you never get a captcha ID, so there is nothing to poll for on /res.php. If your code is looping and waiting, it is waiting on an ID that was never issued.

One thing that trips people up coming from a hosted service: CapSkip is a 2captcha-compatible API that runs on your own machine, so the key is not an account credential and it is not tied to a balance. It is a local access check on the API server. That changes what “wrong key” can even mean, which is why the fixes below are short.

First, check whether key validation is even on

CapSkip ships with key validation optional. When it is off, any non-empty string works and you will never see this error. When it is on, the key has to match exactly.

Open the CapSkip app, go to Settings, and look at the API server section. Two things matter there: whether key validation is enabled, and the exact key string if it is. Copy the key from that screen rather than retyping it. Most reports of ERROR_KEY_DOES_NOT_EXIST end here.

While you are in Settings, confirm the port too. A wrong port gives you a connection error rather than this one, but it is worth checking both at the same time. The setup guide walks through the whole screen.

Pass the key correctly in each SDK

All four SDKs take the same option name, and all four read the same environment variable, CAPSKIP_API_KEY. Set it explicitly while you are debugging so there is no doubt about what is being sent.

# pip install capskip
from capskip import CapSkip

# apiKey defaults to "capskip", which only works when
# key validation is turned off in the app.
solver = CapSkip(
    apiKey="YOUR_API_KEY",
    host="127.0.0.1",
    port=8080,
)
// npm install capskip
const { CapSkip } = require('capskip');

const solver = new CapSkip({
  apiKey: 'YOUR_API_KEY',
  host: '127.0.0.1',
  port: 8080,
});
// composer require capskip/capskip
use CapSkip\CapSkip;

$solver = new CapSkip([
    'apiKey' => 'YOUR_API_KEY',
    'host'   => '127.0.0.1',
    'port'   => 8080,
]);
// dotnet add package CapSkip
using CapSkip;

var solver = new CapSkipClient(
    apiKey: "YOUR_API_KEY",
    host:   "127.0.0.1",
    port:   8080);

Full signatures for every method are on the CAPTCHA solving SDK page.

The three causes worth checking

1. The key never left your code

You set CAPSKIP_API_KEY in a .env file, but nothing loads .env at runtime. Or you exported it in one shell and ran the script in another. The SDK falls back to its default, the default is not your key, and you get the error.

Print what you are about to send. One line, and it settles the question:

import os

# Never print the whole key in a shared log.
key = os.environ.get("CAPSKIP_API_KEY", "<unset>")
print(len(key), repr(key[:4]))

Printing the length catches the case a masked value hides: a key that is present but empty, or one carrying a trailing newline from cat key.txt.

2. The key is right but mangled in the URL

This only bites people calling the raw API. If your key contains characters with a meaning in a query string, they have to be percent-encoded. A + becomes a space, a & ends the parameter early, and a # truncates everything after it.

# Wrong: curl sends this raw and the key gets cut at the &
curl "http://127.0.0.1:8080/in.php?key=ab&cd&method=userrecaptcha"

# Right: let curl encode the parameter for you
curl -G http://127.0.0.1:8080/in.php \
  --data-urlencode "key=ab&cd" \
  --data-urlencode "method=userrecaptcha"

Or POST the parameters as a form body instead, which sidesteps the whole class of problem. MDN has a short reference on percent-encoding if you want the exact character list. The SDKs encode for you, so this cause disappears the moment you switch to one.

3. You changed the key and something is still holding the old one

A long-running worker, a Docker container built with the key baked in, a CI secret, a browser extension configured separately. The app has the new key, one caller still has the old one, and only that caller fails. If some of your requests work and others do not, this is almost always it.

ERROR_KEY_DOES_NOT_EXIST vs ERROR_WRONG_USER_KEY

Two error strings, same family. Treat them as one problem with two shapes.

ErrorWhat it points atFirst thing to check
ERROR_KEY_DOES_NOT_EXISTThe key was read and did not match a known keyThe key string itself, copied from Settings
ERROR_WRONG_USER_KEYKey validation is on and the key sent is wrongWhether validation is on at all, then the string

In the SDKs both surface as an ApiException, so catch that one type and read the message rather than branching on the string.

from capskip import CapSkip, ApiException, NetworkException

solver = CapSkip(apiKey="YOUR_API_KEY")

try:
    result = solver.recaptcha(
        sitekey="YOUR_SITEKEY",
        url="https://example.com/page-with-recaptcha",
    )
except ApiException as e:
    # Key problems land here, with the raw code in the message.
    print("api rejected the request:", e)
except NetworkException as e:
    # The app is not running, or the port is wrong.
    print("cannot reach capskip:", e)

Nearby error codes

If the key checks out, the next few failures at submit time look similar but mean something else entirely.

CodeCauseFix
ERROR_WRONG_METHODThe method parameter is missing or misspelledUse userrecaptcha, turnstile, geetest, post or base64
ERROR_BAD_PARAMETERSA required parameter for that method is absentCheck the method’s parameter list before resubmitting
ERROR_GOOGLEKEYThe sitekey was rejectedRe-read it from the live page, not from cached source
ERROR_PAGEURLThe page URL is missing or malformedSend the full URL including the scheme
Connection refusedThe app is not running or the port differsStart CapSkip, confirm the API server is on

Every code the API can return is listed in the API documentation.

Frequently asked questions

Do I need an API key at all?

Only if key validation is enabled in the app. With it off, any non-empty string is accepted and the SDK default of capskip works fine. The key is a local access check, not an account.

Can ERROR_KEY_DOES_NOT_EXIST mean I ran out of credit?

No. There is no balance to run out of. Solving happens on your own machine, so a key error is always a mismatch between what you sent and what the app expects.

Does the key go in the poll request too?

Yes. /res.php takes the same key parameter as /in.php. If you only fixed the submit call, the poll can still fail on the old value.

Why does my old 2captcha key not work here?

Because it was issued by their service and means nothing to a solver running on your machine. The API shape is the same, the credentials are not. Point your client at 127.0.0.1 and use the key from CapSkip Settings.

Summary

Check whether key validation is on, copy the key from Settings instead of retyping it, confirm the value actually reaches your process, and encode it properly if you are building the URL by hand. That covers effectively every occurrence of error_key_does_not_exist.

The whole class of problem gets smaller when the solver is a local captcha solver you control: no account, no balance, no rotating credentials, and one key you can read off the screen in front of you.