lcobucci/jwt · error · Lcobucci\JWT\Signer\Ecdsa\ConversionFailed

Invalid data. Should start with a sequence.

Error message

Invalid data. Should start with a sequence.

What it means

Thrown by MultibyteStringConverter::fromAsn1 when the input does not begin with the ASN.1 SEQUENCE tag (0x30). DER-encoded ECDSA signatures must start with a SEQUENCE; this guard rejects input that is already in raw r||s concatenation form or otherwise corrupted.

Solutions

  1. Confirm the input is DER-encoded (starts with byte 0x30) before calling fromAsn1
  2. If the signature is raw r||s form, do not call fromAsn1 — use it directly
  3. Decode base64/hex input fully before conversion
  4. Check the transport layer for truncation or corruption of the signature

Example fix

// before
$raw = $converter->fromAsn1($compactJwsSignature, 32);
// after
$der = base64_decode($derBase64Signature, true);
if (ord($der[0]) === 0x30) {
    $raw = $converter->fromAsn1($der, 32);
}
Defensive patterns

Strategy: validation

Validate before calling

if (strlen($signature) < 1 || ord($signature[0]) !== 0x30) { throw new InvalidArgumentException('Not a DER sequence'); }

Try / catch

try { $raw = $converter->fromAsn1($der, 32); } catch (\Jose\Component\Signature\Exception\ConversionFailed $e) { /* treat as raw or reject */ }

Prevention

When it happens

Trigger: Calling fromAsn1() with a raw (non-DER) r||s signature string, or with a base64/hex string that was never decoded to binary, so the first byte is not 0x30.

Common situations: Feeding a JWS/compact signature (raw r||s) into fromAsn1 by mistake, double-decoding base64, or receiving truncated signatures over the wire.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of lcobucci/jwt@375813049c (2026-09-14). Data as JSON: /api/errors/13da27a225a6e36e. Report an issue: GitHub.

Appendix: source

Thrown at src/Signer/Ecdsa/MultibyteStringConverter.php:100

        }

        while (
            substr($data, 0, self::BYTE_SIZE) === self::ASN1_NEGATIVE_INTEGER
            && substr($data, 2, self::BYTE_SIZE) <= self::ASN1_BIG_INTEGER_LIMIT
        ) {
            $data = substr($data, 2, null);
        }

        return $data;
    }

    public function fromAsn1(string $signature, int $length): string
    {
        $message  = bin2hex($signature);
        $position = 0;

        if (self::readAsn1Content($message, $position, self::BYTE_SIZE) !== self::ASN1_SEQUENCE) {
            throw ConversionFailed::incorrectStartSequence();
        }

        // @phpstan-ignore-next-line
        if (self::readAsn1Content($message, $position, self::BYTE_SIZE) === self::ASN1_LENGTH_2BYTES) {
            $position += self::BYTE_SIZE;
        }

        $pointR = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));
        $pointS = self::retrievePositiveInteger(self::readAsn1Integer($message, $position));

        $points = hex2bin(str_pad($pointR, $length, '0', STR_PAD_LEFT) . str_pad($pointS, $length, '0', STR_PAD_LEFT));
        assert(is_string($points));
        assert($points !== '');

        return $points;
    }

    private static function readAsn1Content(string $message, int &$position, int $length): string

View on GitHub (pinned to 375813049c)