BeyondDimension/SteamTools · warning · ApplicationException
Battle.net Authenticator does not have a serial
Error message
Battle.net Authenticator does not have a serial
What it means
Thrown when importing a Battle.net (issuer == 'BattleNet') authenticator whose otpauth URI has no 'serial' query parameter. Battle.net authenticators require a serial alongside the secret, so a missing serial makes the entry unusable.
Source
Thrown at src/BD.WTTS.Client.Plugins.Authenticator/UI/ViewModels/AuthenticatorImportPageViewModel.cs:311
{
throw new ApplicationException("Authenticator does not contain secret");
}
string? counter = query["counter"];
if (uri.Host == "hotp" && string.IsNullOrEmpty(counter))
{
throw new ApplicationException("HOTP authenticator should have a counter");
}
AuthenticatorDTO authenticatorDto = new();
AuthenticatorValueDTO auth;
if (string.Compare(issuer, "BattleNet", StringComparison.OrdinalIgnoreCase) == 0)
{
string? serial = query["serial"];
if (string.IsNullOrEmpty(serial))
{
throw new ApplicationException("Battle.net Authenticator does not have a serial");
}
serial = serial.ToUpper();
if (Regex.IsMatch(serial, @"^[A-Z]{2}-?[\d]{4}-?[\d]{4}-?[\d]{4}$") == false)
{
throw new ApplicationException("Invalid serial for Battle.net Authenticator");
}
auth = new BattleNetAuthenticator();
//char[] decoded = Base32.getInstance().Decode(secret).Select(c => Convert.ToChar(c)).ToArray(); // this is hex string values
//string hex = new string(decoded);
//((BattleNetAuthenticator)auth).SecretKey = Authenticator.StringToByteArray(hex);
((BattleNetAuthenticator)auth).SecretKey = Base32.GetInstance().Decode(secret);
((BattleNetAuthenticator)auth).Serial = serial;
issuer = string.Empty;View on GitHub (pinned to c16ffa08e0)
Solutions
- Re-export the Battle.net authenticator including both secret and serial.
- Obtain the serial from the Battle.net account/agent and append &serial=... to the URI.
- Reject the entry in the UI with a message naming the missing 'serial' field.
- If serial is truly unavailable, import the secret under a generic TOTP issuer instead.
Example fix
// before
if (string.IsNullOrEmpty(serial))
throw new ApplicationException("Battle.net Authenticator does not have a serial");
// after: clearer, parameterised message
if (string.IsNullOrEmpty(serial))
throw new ArgumentException(Strings.Import_BattleNetMissingSerial); Defensive patterns
Strategy: validation
Validate before calling
if (issuer.Equals("BattleNet", StringComparison.OrdinalIgnoreCase))
{
var serial = query["serial"];
if (string.IsNullOrWhiteSpace(serial))
errors.Add(($"Line {n}: Battle.net entry missing 'serial'.", line));
} Type guard
bool BattleNetHasSerial(Uri u, string issuer) =>
!issuer.Equals("BattleNet", StringComparison.OrdinalIgnoreCase)
|| !string.IsNullOrWhiteSpace(HttpUtility.ParseQueryString(u.Query)["serial"]); Try / catch
try { ParseAuthenticator(line); }
catch (ApplicationException ex) when (ex.Message == "Battle.net Authenticator does not have a serial")
{
importErrors.Add(($"Battle.net entry missing serial (line {n}).", line));
continue;
} Prevention
- Detect the BattleNet issuer early and require both 'secret' and 'serial' before parsing.
- Provide a dedicated Battle.net import template showing required fields.
- Validate all required fields per issuer and report missing ones together.
- Document the expected otpauth layout for Battle.net in the import UI.
When it happens
Trigger: Parsing an otpauth entry whose issuer matches BattleNet (case-insensitive) but the query string has no 'serial' key or it is empty.
Common situations: Battle.net export that omitted the serial; URI truncated; entry reconstructed manually without the serial; conversion from a format that didn't store the serial.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid serial for Battle.net Authenticator
- Import only supports otpauth://
- Import only supports otpauth://totp/ or otpauth://hotp/
- Authenticator does not contain secret
- HOTP authenticator should have a counter
AI-assisted analysis of BeyondDimension/SteamTools@c16ffa08e0 (2026-08-13).
Data as JSON: /api/errors/049a2b4d63a57567.
Report an issue: GitHub.