{"record":{"id":"2e4ce04a1179cef3","repo":"lcobucci/jwt","slug":"part-must-be-an-array-with-non-empty-string-keys","errorCode":null,"errorMessage":"{part} must be an array with non-empty-string keys","messagePattern":"(.+?) must be an array with non-empty-string keys","errorType":"exception","errorClass":"Lcobucci\\JWT\\Token\\InvalidTokenStructure","httpStatus":null,"severity":"error","filePath":"src/Token/Parser.php","lineNumber":146,"sourceCode":"            }\n\n            $claims[$claim] = $this->convertDate($claims[$claim]);\n        }\n\n        return $claims;\n    }\n\n    /**\n     * @param array<string, mixed> $array\n     * @param non-empty-string     $part\n     *\n     * @phpstan-assert array<non-empty-string, mixed> $array\n     */\n    private function guardAgainstEmptyStringKeys(array $array, string $part): void\n    {\n        foreach ($array as $key => $value) {\n            if ($key === '') {\n                throw InvalidTokenStructure::arrayExpected($part);\n            }\n        }\n    }\n\n    /** @throws InvalidTokenStructure */\n    private function convertDate(int|float|string $timestamp): DateTimeImmutable\n    {\n        if (! is_numeric($timestamp)) {\n            throw InvalidTokenStructure::dateIsNotParseable($timestamp);\n        }\n\n        $normalizedTimestamp = number_format((float) $timestamp, self::MICROSECOND_PRECISION, '.', '');\n\n        $date = DateTimeImmutable::createFromFormat('U.u', $normalizedTimestamp);\n\n        if ($date === false) {\n            throw InvalidTokenStructure::dateIsNotParseable($normalizedTimestamp);\n        }","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/lcobucci/jwt/blob/375813049c24c7111bda8b6884c57b071ceb2fe7/src/Token/Parser.php#L128-L164","documentation":"The JWT parser requires header and claim arrays to have non-empty string keys, so an entry with an empty-string key ('') makes the token structurally invalid. It is thrown from guardAgainstEmptyStringKeys while parsing the header or claims of a token string. This prevents ambiguous, unnameable header parameters or claims from entering a Token object.","triggerScenarios":"Calling $parser->parse($tokenString) where the decoded token payload JSON contains an object member whose key is the empty string (e.g. {\"\": 1}) in either the header or the claims set.","commonSituations":"Hand-crafted or third-party-minted tokens with malformed JSON objects; misconfigured token issuers; corrupted/modified token strings; passing raw JSON blobs that are not real JWTs to the parser.","solutions":["Fix the token issuer so it never emits claims or header parameters with empty-string names","Regenerate the token from a trusted source and re-verify","Validate token structure (or JSON-decode and check keys) before parsing if tokens come from untrusted input"],"exampleFix":"// before (token payload)\n{\"\": \"oops\", \"sub\": \"123\"}\n// after\n{\"sub\": \"123\"}","handlingStrategy":"validation","validationCode":"$parts = json_decode($payloadJson, true);\nforeach ($parts as $key => $v) {\n    if (!is_string($key) || $key === '') {\n        throw new \\InvalidArgumentException('Token contains a claim/header with an empty name');\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    $token = $parser->parse($jwt);\n} catch (InvalidTokenStructure $e) {\n    // reject token as structurally invalid\n}","preventionTips":["Only accept tokens from issuers you control or trust","Treat InvalidTokenStructure on parse as an authentication failure","Sanity-check raw JSON payloads in tests with malformed fixtures"],"tags":["jwt","parsing","token-structure","php"],"backgroundTag":"schema-validation-failed","analyzedSha":"375813049c24c7111bda8b6884c57b071ceb2fe7","analyzedAt":"2026-09-14T11:12:28.004Z","contentChangedAt":"2026-09-14T11:12:28.004Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}