JustArchiNET/ArchiSteamFarm · error · HttpRequestException

Failed due to error: {0}

Error message

Failed due to error: {0}

What it means

Inside the inventory retry loop, if the HTTP response status is a 4xx client error (response.StatusCode.IsClientErrorCode()), ASF throws an HttpRequestException carrying that status code as the inner status. Client errors are treated as non-retryable — the request itself is wrong or unauthorized.

Source

Thrown at ArchiSteamFarm/Steam/Integration/ArchiWebHandler.cs:346

			await ASF.InventorySemaphore.WaitAsync().ConfigureAwait(false);

			ObjectResponse<InventoryResponse>? response = null;

			try {
				for (byte i = 0; (i < WebBrowser.MaxTries) && (response?.Content is not { Result: EResult.OK } || !response.StatusCode.IsSuccessCode()); i++) {
					if ((i > 0) && (rateLimitingDelay > 0)) {
						await Task.Delay(rateLimitingDelay).ConfigureAwait(false);
					}

					response = await UrlGetToJsonObjectWithSession<InventoryResponse>(request, requestOptions: WebBrowser.ERequestOptions.ReturnClientErrors | WebBrowser.ERequestOptions.ReturnServerErrors | WebBrowser.ERequestOptions.AllowInvalidBodyOnErrors | WebBrowser.ERequestOptions.SteamWafWorkarounds, rateLimitingDelay: rateLimitingDelay).ConfigureAwait(false);

					if (response == null) {
						throw new HttpRequestException(Strings.FormatErrorObjectIsNull(nameof(response)));
					}

					if (response.StatusCode.IsClientErrorCode()) {
						throw new HttpRequestException(Strings.FormatWarningFailedWithError(response.StatusCode), null, response.StatusCode);
					}

					if (response.StatusCode.IsServerErrorCode()) {
						if (string.IsNullOrEmpty(response.Content?.ErrorText)) {
							// This is a generic server error without a reason, try again
							continue;
						}

						Bot.ArchiLogger.LogGenericDebug(Strings.FormatWarningFailedWithError(response.Content.ErrorText));

						// Try to interpret the failure reason and see if we should try again
						switch (response.Content.ErrorCode) {
							case EResult.Busy:
							case EResult.DuplicateRequest:
							case EResult.Fail:
							case EResult.RemoteCallFailed:
							case EResult.ServiceUnavailable:
							case EResult.Timeout:

View on GitHub (pinned to fe57c4129f)

Solutions

  1. Refresh the bot's web session / access token and retry.
  2. Confirm the target inventory is public (or owned by the bot).
  3. Verify the constructed inventory URL is correct for the account and app/context.
  4. If 429, reduce request frequency and respect rate limiting.
Defensive patterns

Strategy: try-catch

Validate before calling

// Refresh session if it is likely stale before a client error surfaces.
if (sessionLikelyExpired) await bot.ArchiWebHandler.RefreshSession();

Try / catch

try { await foreach (var a in webHandler.GetInventoryAsync(steamID)) { /* ... */ } }
catch (HttpRequestException ex) when (ex.StatusCode.HasValue && (int)ex.StatusCode.Value is >= 400 and <= 499) {
    // 4xx client error; refresh session or correct target, do not blind-retry
}

Prevention

When it happens

Trigger: Steam community returns a 4xx (e.g. 401 unauthorized session, 403 forbidden/private inventory, 404 not found, 429 rate-limited occasionally classified here) for the inventory endpoint.

Common situations: Expired/invalid access token (401); target inventory set to private (403); wrong profile/inventory URL (404); stale session cookies; the bot account losing web privileges.

Related errors


AI-assisted analysis of JustArchiNET/ArchiSteamFarm@fe57c4129f (2026-08-13). Data as JSON: /api/errors/391cc72808be0762. Report an issue: GitHub.