{"record":{"id":"60c3817c3d10a458","repo":"w7corp/easywechat","slug":"missing-platform-certificate","errorCode":null,"errorMessage":"Missing platform certificate.","messagePattern":"Missing platform certificate\\.","errorType":"exception","errorClass":"InvalidConfigException","httpStatus":null,"severity":"error","filePath":"src/Pay/Client.php","lineNumber":198,"sourceCode":"        $uri = '/'.ltrim((new Uri($url))->getPath(), '/');\n\n        foreach (self::V3_URI_PREFIXES as $prefix) {\n            if (str_starts_with($uri, $prefix)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * @throws InvalidArgumentException\n     */\n    public function withSerialHeader(?string $serial = null): static\n    {\n        $platformCerts = $this->merchant->getPlatformCerts();\n        if (empty($platformCerts)) {\n            throw new InvalidConfigException('Missing platform certificate.');\n        }\n\n        $serial ??= array_key_first($platformCerts);\n        $this->withHeader('Wechatpay-Serial', $serial);\n\n        return $this;\n    }\n\n    /**\n     * @param  array<int, mixed>  $arguments\n     */\n    public function __call(string $name, array $arguments): mixed\n    {\n        if (\\str_starts_with($name, 'with')) {\n            return $this->handleMagicWithCall($name, $arguments[0] ?? null);\n        }\n\n        return $this->client->$name(...$arguments);","sourceCodeStart":180,"sourceCodeEnd":216,"githubUrl":"https://github.com/w7corp/easywechat/blob/f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8/src/Pay/Client.php#L180-L216","documentation":"Thrown by Pay/Client::withSerialHeader() when the merchant config carries no platform certificates, so there is no serial number to put in the Wechatpay-Serial header. Sensitive-request encryption and certificate-related endpoints require telling WeChat Pay which platform cert/public key you encrypt with; with zero certs loaded there is nothing to choose from.","triggerScenarios":"Calling pay APIs that trigger withSerialHeader() — e.g. POST with encryption (marketing/redemption codes), GET /v3/certificates flow setups — when the Merchant was constructed without the platformCerts array (default []) or it resolved empty.","commonSituations":"Fresh integration that only set mchId/privateKey/certificate/secretKey but never downloaded platform certs; certs loaded from env var that is empty; passing an empty string instead of an array; new deployments after cert rotation removed old files.","solutions":["Download current platform certificate(s) via GET /v3/certificates (the official CertificateDownloader tool) and pass them as the platformCerts array when constructing Merchant","Load the PEM file contents (or PublicKey instances) from a persistent path instead of env-only config","Verify the array is non-empty right after building the Application and fail fast at boot"],"exampleFix":"// before\n$merchant = new \\EasyWeChat\\Pay\\Merchant($mchId, $privateKey, $cert, $secretKey, null /* v2key */);\n// no platform certs -> withSerialHeader() throws\n// after\n$merchant = new \\EasyWeChat\\Pay\\Merchant(\n    $mchId, $privateKey, $cert, $secretKey, $v2Key,\n    [ file_get_contents('/certs/wechatpay-platform.pem') ]\n);","handlingStrategy":"validation","validationCode":"$merchant = new Merchant($mchId, $priv, $cert, $key, $v2, $platformCerts);\nif (count($merchant->getPlatformCerts()) === 0) {\n    throw new \\RuntimeException('No WeChat Pay platform certs loaded - run CertificateDownloader');\n}","typeGuard":"function hasPlatformCerts(\\EasyWeChat\\Pay\\Contracts\\Merchant $m): bool\n{\n    return count($m->getPlatformCerts()) > 0;\n}","tryCatchPattern":"try {\n    $app->client->withSerialHeader();\n} catch (\\EasyWeChat\\Kernel\\Exceptions\\InvalidConfigException $e) {\n    // download certs, rebuild Merchant, retry once\n}","preventionTips":["Download platform certs during provisioning and load them from a known path","Boot-time assertions on merchant config completeness","Track WeChat cert/public-key rotation notices and keep multiple generations loaded"],"tags":["wechat-pay","platform-certificate","merchant-config","invalid-config"],"backgroundTag":"missing-platform-certificate","analyzedSha":"f0cf0a8b8361417ed683b8246d0ecbaf0aafcaa8","analyzedAt":"2026-08-21T05:29:19.565Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}