w7corp/easywechat · error · InvalidConfigException

Missing v2 secret key.

Error message

Missing v2 secret key.

What it means

Thrown by Utils::createV2Signature() (src/Pay/Utils.php:182) when the merchant has no WeChat Pay APIv2 key. This method implements legacy v2 signing: ksort() the params, append the key as `key`, then produce an HMAC-SHA256 or MD5 signature over the urldecoded query string. The v2 key (config `v2_secret_key`, see src/Pay/Merchant.php:31 and src/Pay/Application.php:46) is a separate 32-character key from the v3 `secret_key`, so a fully working v3 setup can still hit this. It is raised as InvalidConfigException before any crypto runs, via empty() on getV2SecretKey().

Source

Thrown at src/Pay/Utils.php:182

            throw new InvalidConfigException('Missing platform certificate.');
        }

        if (! openssl_public_encrypt($plaintext, $encrypted, $platformCert, OPENSSL_PKCS1_OAEP_PADDING)) {
            throw new EncryptionFailureException('Encrypt failed.');
        }

        return base64_encode($encrypted);
    }

    /**
     * @throws InvalidConfigException
     */
    public function createV2Signature(array $params): string
    {
        $secretKey = $this->merchant->getV2SecretKey();

        if (empty($secretKey)) {
            throw new InvalidConfigException('Missing v2 secret key.');
        }

        ksort($params);

        $params['key'] = $secretKey;

        $message = urldecode(http_build_query($params));

        if ($params['signType'] === 'HMAC-SHA256') {
            $signature = hash_hmac('sha256', $message, $secretKey);
        } else {
            $signature = md5($message);
        }

        return strtoupper($signature);
    }
}

View on GitHub (pinned to f0cf0a8b83)

Solutions

  1. Add 'v2_secret_key' => '<32-char key>' to the pay config — get it in the WeChat Pay merchant console under Account Center > API Security > APIv2 key (账户中心 > API安全 > APIv2密钥).
  2. If the integration only needs v3, switch the offending call to the v3 API equivalent and drop the v2 signing path.
  3. Verify the value actually loads where the call runs: dump the pay config, check .env, config cache and environment-specific overrides.
  4. Confirm the key is exactly 32 characters with no surrounding whitespace or quotes.

Example fix

// before
$config = [
    'mch_id' => '1900000000',
    'secret_key' => '<api-v3-key>',
    'private_key' => '...',
    'certificate' => '...',
    // v2_secret_key missing -> createV2Signature() throws
];
$sign = $app->getUtils()->createV2Signature($params);

// after
$config = [
    'mch_id' => '1900000000',
    'secret_key' => '<api-v3-key>',
    'private_key' => '...',
    'certificate' => '...',
    'v2_secret_key' => '<32-char-api-v2-key>',
];
$sign = $app->getUtils()->createV2Signature($params);
Defensive patterns

Strategy: validation

Validate before calling

use EasyWeChat\Kernel\Exceptions\InvalidConfigException;

if (empty($app->getMerchant()->getV2SecretKey())) {
    throw new InvalidConfigException(
        'WeChat Pay v2_secret_key is not configured; set it before using v2 signing.'
    );
}

$sign = $app->getUtils()->createV2Signature($params);

Try / catch

use EasyWeChat\Kernel\Exceptions\InvalidConfigException;

try {
    $sign = $utils->createV2Signature($params);
} catch (InvalidConfigException $e) {
    // Config problem, not runtime: surface it — never send unsigned v2 requests
    Log::error('wechat-pay v2 signing unavailable: {msg}', ['msg' => $e->getMessage()]);
    throw $e;
}

Prevention

When it happens

Trigger: Calling Utils::createV2Signature() or any v2-style signing path (LegacySignature, src/Pay/LegacySignature.php:48-57), or handling v2 XML callbacks whose req_info is decrypted with md5(v2 key) (src/Pay/Server.php:223-226), while the pay config has no `v2_secret_key` set — Application.php:46 casts the missing value to an empty string, so getV2SecretKey() returns '' and empty() trips.

Common situations: Config only sets v3 credentials (secret_key, private_key, certificate) but a refund, red-pack or other legacy endpoint still uses v2; key pasted under the wrong config name; .env value not loaded or config cache stale in one environment; secrets manager returning an empty string.

Related errors


AI-assisted analysis of w7corp/easywechat@f0cf0a8b83 (2026-08-21). Data as JSON: /api/errors/140e8b948e3a68cf. Report an issue: GitHub.