From df4c0fd0f564f85a20dd9a175d0017ff381e677b Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Thu, 9 Jul 2026 00:57:38 +0200 Subject: [PATCH 1/4] Return an error instead of throwing on invalid UTF-8 in deserialisation helpers --- ...i_pablo.lamela_nonthrowing_utf8_decode.yml | 6 +++ .../Internal/SomeAddressVerificationKey.hs | 8 +++- .../Cardano/Api/Serialise/DeserialiseAnyOf.hs | 39 ++++++++++--------- 3 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 .changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml diff --git a/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml new file mode 100644 index 0000000000..9e59aafaf6 --- /dev/null +++ b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml @@ -0,0 +1,6 @@ +description: | + Fixed `deserialiseInput`, `deserialiseInputAnyOf` and `deserialiseAnyVerificationKeyBech32` (and thereby `deserialiseAnyVerificationKey`) to return an error instead of throwing an impure exception when the input is not valid UTF-8. +kind: +- bugfix +pr: 1249 +project: cardano-api diff --git a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs index 1d7fa9ebef..845c2f3c3f 100644 --- a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs +++ b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs @@ -28,6 +28,7 @@ import Cardano.Api.Serialise.TextEnvelope.Internal import Cardano.Chain.Common qualified as Common import Cardano.Crypto.Signing qualified as Crypto +import Codec.Binary.Bech32 qualified as Bech32 import Data.Aeson qualified as Aeson import Data.Bifunctor (first) import Data.ByteString (ByteString) @@ -142,8 +143,11 @@ deserialiseAnyVerificationKey bs = deserialiseAnyVerificationKeyBech32 :: ByteString -> Either Bech32DecodeError SomeAddressVerificationKey -deserialiseAnyVerificationKeyBech32 = - deserialiseAnyOfFromBech32 allBech32VerKey . Text.decodeUtf8 +deserialiseAnyVerificationKeyBech32 bs = + case Text.decodeUtf8' bs of + -- The input is not valid UTF-8, so it cannot be valid Bech32. + Left _ -> Left $ Bech32DecodingError $ Bech32.StringToDecodeContainsInvalidChars [] + Right text -> deserialiseAnyOfFromBech32 allBech32VerKey text where allBech32VerKey :: [FromSomeType SerialiseAsBech32 SomeAddressVerificationKey] diff --git a/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs b/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs index 6fce35def4..64f10fe2bc 100644 --- a/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs +++ b/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs @@ -35,7 +35,6 @@ import Data.ByteString.Char8 qualified as BSC import Data.Char (toLower) import Data.Data import Data.List.NonEmpty (NonEmpty) -import Data.Text (Text) import Data.Text.Encoding qualified as Text import GHC.Exts (IsList (..)) import Prettyprinter @@ -107,9 +106,6 @@ deserialiseInput deserialiseInput acceptedFormats inputBs = go (toList acceptedFormats) where - inputText :: Text - inputText = Text.decodeUtf8 inputBs - go :: [InputFormat a] -> Either InputDecodeError a go [] = Left InputInvalidError go (kf : kfs) = @@ -140,12 +136,16 @@ deserialiseInput acceptedFormats inputBs = deserialiseBech32 :: SerialiseAsBech32 a => DeserialiseInputResult a deserialiseBech32 = - case deserialiseFromBech32 inputText of - Right res -> DeserialiseInputSuccess res - -- The input was not valid Bech32. - Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch - -- The input was valid Bech32, but some other error occurred. - Left err -> DeserialiseInputError $ InputBech32DecodeError err + case Text.decodeUtf8' inputBs of + -- The input was not valid UTF-8, so it cannot be valid Bech32. + Left _ -> DeserialiseInputErrorFormatMismatch + Right inputText -> + case deserialiseFromBech32 inputText of + Right res -> DeserialiseInputSuccess res + -- The input was not valid Bech32. + Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch + -- The input was valid Bech32, but some other error occurred. + Left err -> DeserialiseInputError $ InputBech32DecodeError err deserialiseHex :: SerialiseAsRawBytes a => DeserialiseInputResult a deserialiseHex @@ -179,9 +179,6 @@ deserialiseInputAnyOf bech32Types textEnvTypes inputBs = DeserialiseInputError err -> Left err DeserialiseInputErrorFormatMismatch -> Left InputInvalidError where - inputText :: Text - inputText = Text.decodeUtf8 inputBs - orTry :: DeserialiseInputResult b -> DeserialiseInputResult b @@ -209,12 +206,16 @@ deserialiseInputAnyOf bech32Types textEnvTypes inputBs = deserialiseBech32 :: DeserialiseInputResult b deserialiseBech32 = - case deserialiseAnyOfFromBech32 bech32Types inputText of - Right res -> DeserialiseInputSuccess res - -- The input was not valid Bech32. - Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch - -- The input was valid Bech32, but some other error occurred. - Left err -> DeserialiseInputError $ InputBech32DecodeError err + case Text.decodeUtf8' inputBs of + -- The input was not valid UTF-8, so it cannot be valid Bech32. + Left _ -> DeserialiseInputErrorFormatMismatch + Right inputText -> + case deserialiseAnyOfFromBech32 bech32Types inputText of + Right res -> DeserialiseInputSuccess res + -- The input was not valid Bech32. + Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch + -- The input was valid Bech32, but some other error occurred. + Left err -> DeserialiseInputError $ InputBech32DecodeError err -- | Read formatted file readFormattedFile From 3fec64a55e6d37244928d4de112c380a8f087567 Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Fri, 10 Jul 2026 03:36:11 +0200 Subject: [PATCH 2/4] Render the UTF-8 decoding error via a new Bech32InvalidUtf8 constructor Instead of discarding the UnicodeException and fabricating StringToDecodeContainsInvalidChars [], deserialiseAnyVerificationKeyBech32 now returns Bech32InvalidUtf8 carrying the rendered decoding error. --- ...0000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml | 2 +- .../Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs | 5 +++-- cardano-api/src/Cardano/Api/Serialise/Bech32.hs | 5 +++++ .../test/cardano-api-golden/Test/Golden/ErrorsSpec.hs | 1 + .../Bech32InvalidUtf8.txt | 1 + 5 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt diff --git a/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml index 9e59aafaf6..ed0f28f5d0 100644 --- a/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml +++ b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml @@ -1,5 +1,5 @@ description: | - Fixed `deserialiseInput`, `deserialiseInputAnyOf` and `deserialiseAnyVerificationKeyBech32` (and thereby `deserialiseAnyVerificationKey`) to return an error instead of throwing an impure exception when the input is not valid UTF-8. + Fixed `deserialiseInput`, `deserialiseInputAnyOf` and `deserialiseAnyVerificationKeyBech32` (and thereby `deserialiseAnyVerificationKey`) to return an error instead of throwing an impure exception when the input is not valid UTF-8. Added a `Bech32InvalidUtf8` constructor to `Bech32DecodeError`, which carries the rendered UTF-8 decoding error. kind: - bugfix pr: 1249 diff --git a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs index 845c2f3c3f..b6ccbd64eb 100644 --- a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs +++ b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs @@ -28,11 +28,12 @@ import Cardano.Api.Serialise.TextEnvelope.Internal import Cardano.Chain.Common qualified as Common import Cardano.Crypto.Signing qualified as Crypto -import Codec.Binary.Bech32 qualified as Bech32 +import Control.Exception (displayException) import Data.Aeson qualified as Aeson import Data.Bifunctor (first) import Data.ByteString (ByteString) import Data.Text (Text) +import Data.Text qualified as Text import Data.Text.Encoding qualified as Text import Formatting (build, sformat, (%)) @@ -146,7 +147,7 @@ deserialiseAnyVerificationKeyBech32 deserialiseAnyVerificationKeyBech32 bs = case Text.decodeUtf8' bs of -- The input is not valid UTF-8, so it cannot be valid Bech32. - Left _ -> Left $ Bech32DecodingError $ Bech32.StringToDecodeContainsInvalidChars [] + Left err -> Left $ Bech32InvalidUtf8 $ Text.pack $ displayException err Right text -> deserialiseAnyOfFromBech32 allBech32VerKey text where allBech32VerKey diff --git a/cardano-api/src/Cardano/Api/Serialise/Bech32.hs b/cardano-api/src/Cardano/Api/Serialise/Bech32.hs index 6fa1840434..c4633bb847 100644 --- a/cardano-api/src/Cardano/Api/Serialise/Bech32.hs +++ b/cardano-api/src/Cardano/Api/Serialise/Bech32.hs @@ -149,6 +149,9 @@ data Bech32DecodeError -- ^ Expected header !Text -- ^ Unexpected header + | -- | The input is not valid UTF-8, so it cannot be a Bech32-encoded + -- string. The field contains the rendered UTF-8 decoding error. + Bech32InvalidUtf8 !Text deriving (Eq, Show, Data) instance Error Bech32DecodeError where @@ -181,3 +184,5 @@ instance Error Bech32DecodeError where [ "Unexpected CIP-129 Bech32 header: the actual header is " <> pshow actual , ", but it was expected to be " <> pshow expected ] + Bech32InvalidUtf8 decodeErr -> + "The Bech32-encoded string is not valid UTF-8: " <> pretty decodeErr diff --git a/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs b/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs index 08c26077a7..5a63ce34a4 100644 --- a/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs +++ b/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs @@ -159,6 +159,7 @@ test_Bech32DecodeError = , Bech32DeserialiseFromBytesError bytestring , Bech32WrongPrefix text text , Bech32UnexpectedHeader text text + , Bech32InvalidUtf8 text ] test_InputDecodeError :: TestTree diff --git a/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt b/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt new file mode 100644 index 0000000000..5338dd2070 --- /dev/null +++ b/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt @@ -0,0 +1 @@ +The Bech32-encoded string is not valid UTF-8: \ No newline at end of file From bc818047a0e79948dc7e7fbbef56419cf48c5379 Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Fri, 10 Jul 2026 03:36:12 +0200 Subject: [PATCH 3/4] Separate flow from error handling in deserialiseBech32 helpers Restructure the bech32 branches of deserialiseInput and deserialiseInputAnyOf as suggested in review. --- .../Cardano/Api/Serialise/DeserialiseAnyOf.hs | 48 ++++++++++--------- 1 file changed, 26 insertions(+), 22 deletions(-) diff --git a/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs b/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs index 64f10fe2bc..abbc738907 100644 --- a/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs +++ b/cardano-api/src/Cardano/Api/Serialise/DeserialiseAnyOf.hs @@ -135,17 +135,19 @@ deserialiseInput acceptedFormats inputBs = Left _ -> DeserialiseInputErrorFormatMismatch deserialiseBech32 :: SerialiseAsBech32 a => DeserialiseInputResult a - deserialiseBech32 = - case Text.decodeUtf8' inputBs of - -- The input was not valid UTF-8, so it cannot be valid Bech32. - Left _ -> DeserialiseInputErrorFormatMismatch - Right inputText -> - case deserialiseFromBech32 inputText of - Right res -> DeserialiseInputSuccess res - -- The input was not valid Bech32. - Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch - -- The input was valid Bech32, but some other error occurred. - Left err -> DeserialiseInputError $ InputBech32DecodeError err + deserialiseBech32 = either id fromBech32 $ decodeText inputBs + where + -- The input was not valid UTF-8, so it cannot be valid Bech32. + decodeText = + first (const DeserialiseInputErrorFormatMismatch) + . Text.decodeUtf8' + fromBech32 text = + case deserialiseFromBech32 text of + Right res -> DeserialiseInputSuccess res + -- The input was not valid Bech32. + Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch + -- The input was valid Bech32, but some other error occurred. + Left err -> DeserialiseInputError $ InputBech32DecodeError err deserialiseHex :: SerialiseAsRawBytes a => DeserialiseInputResult a deserialiseHex @@ -205,17 +207,19 @@ deserialiseInputAnyOf bech32Types textEnvTypes inputBs = Left _ -> DeserialiseInputErrorFormatMismatch deserialiseBech32 :: DeserialiseInputResult b - deserialiseBech32 = - case Text.decodeUtf8' inputBs of - -- The input was not valid UTF-8, so it cannot be valid Bech32. - Left _ -> DeserialiseInputErrorFormatMismatch - Right inputText -> - case deserialiseAnyOfFromBech32 bech32Types inputText of - Right res -> DeserialiseInputSuccess res - -- The input was not valid Bech32. - Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch - -- The input was valid Bech32, but some other error occurred. - Left err -> DeserialiseInputError $ InputBech32DecodeError err + deserialiseBech32 = either id fromBech32 $ decodeText inputBs + where + -- The input was not valid UTF-8, so it cannot be valid Bech32. + decodeText = + first (const DeserialiseInputErrorFormatMismatch) + . Text.decodeUtf8' + fromBech32 text = + case deserialiseAnyOfFromBech32 bech32Types text of + Right res -> DeserialiseInputSuccess res + -- The input was not valid Bech32. + Left (Bech32DecodingError _) -> DeserialiseInputErrorFormatMismatch + -- The input was valid Bech32, but some other error occurred. + Left err -> DeserialiseInputError $ InputBech32DecodeError err -- | Read formatted file readFormattedFile From b824fdbdcabcc64ab4c87422bbc7a5a0cf70ea5b Mon Sep 17 00:00:00 2001 From: Pablo Lamela Date: Tue, 14 Jul 2026 01:38:06 +0000 Subject: [PATCH 4/4] Store the UnicodeException itself in Bech32InvalidUtf8 Instead of pre-rendering the UTF-8 decoding error to Text at the construction site, keep the UnicodeException in the constructor and render it in the Error instance, so the rendering lives in a single place. This needs a Data instance for UnicodeException, derived in Cardano.Api.Internal.Orphans.Misc alongside the existing orphan Data instances for third-party error types. --- ...00_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml | 2 +- cardano-api/src/Cardano/Api/Internal/Orphans/Misc.hs | 2 ++ .../Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs | 4 +--- cardano-api/src/Cardano/Api/Serialise/Bech32.hs | 7 ++++--- .../test/cardano-api-golden/Test/Golden/ErrorsSpec.hs | 6 +++++- .../Bech32InvalidUtf8.txt | 2 +- 6 files changed, 14 insertions(+), 9 deletions(-) diff --git a/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml index ed0f28f5d0..7d4cbe7d50 100644 --- a/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml +++ b/.changes/20260708_140000_cardano-api_pablo.lamela_nonthrowing_utf8_decode.yml @@ -1,5 +1,5 @@ description: | - Fixed `deserialiseInput`, `deserialiseInputAnyOf` and `deserialiseAnyVerificationKeyBech32` (and thereby `deserialiseAnyVerificationKey`) to return an error instead of throwing an impure exception when the input is not valid UTF-8. Added a `Bech32InvalidUtf8` constructor to `Bech32DecodeError`, which carries the rendered UTF-8 decoding error. + Fixed `deserialiseInput`, `deserialiseInputAnyOf` and `deserialiseAnyVerificationKeyBech32` (and thereby `deserialiseAnyVerificationKey`) to return an error instead of throwing an impure exception when the input is not valid UTF-8. Added a `Bech32InvalidUtf8` constructor to `Bech32DecodeError`, which carries the UTF-8 decoding error. kind: - bugfix pr: 1249 diff --git a/cardano-api/src/Cardano/Api/Internal/Orphans/Misc.hs b/cardano-api/src/Cardano/Api/Internal/Orphans/Misc.hs index d9d04cdd21..1378661809 100644 --- a/cardano-api/src/Cardano/Api/Internal/Orphans/Misc.hs +++ b/cardano-api/src/Cardano/Api/Internal/Orphans/Misc.hs @@ -63,6 +63,8 @@ deriving instance Data Bech32.DecodingError deriving instance Data Bech32.CharPosition +deriving instance Data T.UnicodeException + -- | These instances originally existed on the Lovelace type. -- As the Lovelace type is deleted and we use L.Coin instead, -- these instances are added to L.Coin. The instances are diff --git a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs index b6ccbd64eb..4747063af5 100644 --- a/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs +++ b/cardano-api/src/Cardano/Api/Key/Internal/SomeAddressVerificationKey.hs @@ -28,12 +28,10 @@ import Cardano.Api.Serialise.TextEnvelope.Internal import Cardano.Chain.Common qualified as Common import Cardano.Crypto.Signing qualified as Crypto -import Control.Exception (displayException) import Data.Aeson qualified as Aeson import Data.Bifunctor (first) import Data.ByteString (ByteString) import Data.Text (Text) -import Data.Text qualified as Text import Data.Text.Encoding qualified as Text import Formatting (build, sformat, (%)) @@ -147,7 +145,7 @@ deserialiseAnyVerificationKeyBech32 deserialiseAnyVerificationKeyBech32 bs = case Text.decodeUtf8' bs of -- The input is not valid UTF-8, so it cannot be valid Bech32. - Left err -> Left $ Bech32InvalidUtf8 $ Text.pack $ displayException err + Left err -> Left $ Bech32InvalidUtf8 err Right text -> deserialiseAnyOfFromBech32 allBech32VerKey text where allBech32VerKey diff --git a/cardano-api/src/Cardano/Api/Serialise/Bech32.hs b/cardano-api/src/Cardano/Api/Serialise/Bech32.hs index c4633bb847..299b0f5112 100644 --- a/cardano-api/src/Cardano/Api/Serialise/Bech32.hs +++ b/cardano-api/src/Cardano/Api/Serialise/Bech32.hs @@ -28,6 +28,7 @@ import Data.ByteString (ByteString) import Data.Data (Data) import Data.List qualified as List import Data.Set (Set) +import Data.Text.Encoding.Error (UnicodeException) import GHC.Exts (IsList (..)) import GHC.Stack @@ -150,8 +151,8 @@ data Bech32DecodeError !Text -- ^ Unexpected header | -- | The input is not valid UTF-8, so it cannot be a Bech32-encoded - -- string. The field contains the rendered UTF-8 decoding error. - Bech32InvalidUtf8 !Text + -- string. The field contains the UTF-8 decoding error. + Bech32InvalidUtf8 !UnicodeException deriving (Eq, Show, Data) instance Error Bech32DecodeError where @@ -185,4 +186,4 @@ instance Error Bech32DecodeError where , ", but it was expected to be " <> pshow expected ] Bech32InvalidUtf8 decodeErr -> - "The Bech32-encoded string is not valid UTF-8: " <> pretty decodeErr + "The Bech32-encoded string is not valid UTF-8: " <> prettyError decodeErr diff --git a/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs b/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs index 5a63ce34a4..64156e35c7 100644 --- a/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs +++ b/cardano-api/test/cardano-api-golden/Test/Golden/ErrorsSpec.hs @@ -61,6 +61,7 @@ import Data.Maybe import Data.Set qualified as Set import Data.Text qualified as Text import Data.Text.Encoding qualified as Text +import Data.Text.Encoding.Error (UnicodeException (..)) import Data.Word import GHC.Exts (IsList (..)) import GHC.Stack (HasCallStack) @@ -91,6 +92,9 @@ bytestring = "" :: ByteString lazyBytestring :: LBS.ByteString lazyBytestring = "" :: LBS.ByteString +unicodeException :: UnicodeException +unicodeException = DecodeError "" (Just 0xc3) + stakePoolVerKey1 :: VerificationKey StakePoolKey stakePoolVerKey1 = getVerificationKey $ deterministicSigningKey AsStakePoolKey (Crypto.mkSeedFromBytes seed1) @@ -159,7 +163,7 @@ test_Bech32DecodeError = , Bech32DeserialiseFromBytesError bytestring , Bech32WrongPrefix text text , Bech32UnexpectedHeader text text - , Bech32InvalidUtf8 text + , Bech32InvalidUtf8 unicodeException ] test_InputDecodeError :: TestTree diff --git a/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt b/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt index 5338dd2070..e63d7984ca 100644 --- a/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt +++ b/cardano-api/test/cardano-api-golden/files/errors/Cardano.Api.Serialise.Bech32.Bech32DecodeError/Bech32InvalidUtf8.txt @@ -1 +1 @@ -The Bech32-encoded string is not valid UTF-8: \ No newline at end of file +The Bech32-encoded string is not valid UTF-8: Cannot decode byte '\xc3': \ No newline at end of file