Deduplicate UBJSON/BJData length-type error message

The "expected length type specification" parse error was built with an
identical if/else block in both get_ubjson_string() and
get_ubjson_size_value(), each branching on the input format to pick the
marker list. Extract a single unexpected_length_type_message() helper that
selects the markers via a ternary and appends the caller-supplied infix,
removing four near-duplicate message strings and centralizing the marker
list. Error messages are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Tv6SnfYbcx8y3y4PrECcto
diff --git a/include/nlohmann/detail/input/binary_reader.hpp b/include/nlohmann/detail/input/binary_reader.hpp
index 4f8ab79..3a1a82e 100644
--- a/include/nlohmann/detail/input/binary_reader.hpp
+++ b/include/nlohmann/detail/input/binary_reader.hpp
@@ -1870,6 +1870,24 @@
     }
 
     /*!
+    @brief create the error message for a missing/invalid length-type marker
+
+    Used both when reading a UBJSON/BJData string and when reading an optimized
+    container size. The accepted markers depend on the input format, and the
+    size variant appends " after '#'" via @a infix.
+
+    @param[in] last_token  the offending byte as returned by get_token_string()
+    @param[in] infix       extra context inserted after the marker list
+    @return the formatted error message
+    */
+    std::string unexpected_length_type_message(const std::string& last_token, const char* infix) const
+    {
+        return concat("expected length type specification (",
+                      input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L",
+                      ")", infix, "; last byte: 0x", last_token);
+    }
+
+    /*!
     @brief reads a UBJSON string
 
     This function is either called after reading the 'S' byte explicitly
@@ -1961,17 +1979,8 @@
                 break;
         }
         auto last_token = get_token_string();
-        std::string message;
-
-        if (input_format != input_format_t::bjdata)
-        {
-            message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
-        }
-        else
-        {
-            message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
-        }
-        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                exception_message(input_format, unexpected_length_type_message(last_token, ""), "string"), nullptr));
     }
 
     /*!
@@ -2250,17 +2259,8 @@
                 break;
         }
         auto last_token = get_token_string();
-        std::string message;
-
-        if (input_format != input_format_t::bjdata)
-        {
-            message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
-        }
-        else
-        {
-            message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
-        }
-        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                exception_message(input_format, unexpected_length_type_message(last_token, " after '#'"), "size"), nullptr));
     }
 
     /*!
diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp
index 580b9bd..d8cc296 100644
--- a/single_include/nlohmann/json.hpp
+++ b/single_include/nlohmann/json.hpp
@@ -12419,6 +12419,24 @@
     }
 
     /*!
+    @brief create the error message for a missing/invalid length-type marker
+
+    Used both when reading a UBJSON/BJData string and when reading an optimized
+    container size. The accepted markers depend on the input format, and the
+    size variant appends " after '#'" via @a infix.
+
+    @param[in] last_token  the offending byte as returned by get_token_string()
+    @param[in] infix       extra context inserted after the marker list
+    @return the formatted error message
+    */
+    std::string unexpected_length_type_message(const std::string& last_token, const char* infix) const
+    {
+        return concat("expected length type specification (",
+                      input_format == input_format_t::bjdata ? "U, i, u, I, m, l, M, L" : "U, i, I, l, L",
+                      ")", infix, "; last byte: 0x", last_token);
+    }
+
+    /*!
     @brief reads a UBJSON string
 
     This function is either called after reading the 'S' byte explicitly
@@ -12510,17 +12528,8 @@
                 break;
         }
         auto last_token = get_token_string();
-        std::string message;
-
-        if (input_format != input_format_t::bjdata)
-        {
-            message = "expected length type specification (U, i, I, l, L); last byte: 0x" + last_token;
-        }
-        else
-        {
-            message = "expected length type specification (U, i, u, I, m, l, M, L); last byte: 0x" + last_token;
-        }
-        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "string"), nullptr));
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                exception_message(input_format, unexpected_length_type_message(last_token, ""), "string"), nullptr));
     }
 
     /*!
@@ -12799,17 +12808,8 @@
                 break;
         }
         auto last_token = get_token_string();
-        std::string message;
-
-        if (input_format != input_format_t::bjdata)
-        {
-            message = "expected length type specification (U, i, I, l, L) after '#'; last byte: 0x" + last_token;
-        }
-        else
-        {
-            message = "expected length type specification (U, i, u, I, m, l, M, L) after '#'; last byte: 0x" + last_token;
-        }
-        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read, exception_message(input_format, message, "size"), nullptr));
+        return sax->parse_error(chars_read, last_token, parse_error::create(113, chars_read,
+                                exception_message(input_format, unexpected_length_type_message(last_token, " after '#'"), "size"), nullptr));
     }
 
     /*!