Redirects for HEAD requests

Hello, I’m using version 3.11.0 and noticed that HEAD requests don’t seem to follow redirects? Here’s an example similar to the sample code from the docs, modified accordingly:

    val syncBackend = HttpClientSyncBackend()
    val response = basicRequest
      .head(uri"https://dts.podtrac.com/redirect.mp3/rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3")
      .send(syncBackend)

This returns a single response like so:

302 , headers: expires: -1, cache-control: no-cache, no-store, must-revalidate, location: https://rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3, date: Wed, 14 May 2025 16:51:43 GMT, :status: 302, pragma: no-cache, body: ()

However that doesn’t match the observed behavior using httpie, which eventually returns a 200.

I even explicitly set followRedirects(true) but that hasn’t changed the behavior. Did I misunderstand something?

Thanks,

-Dragos

I’m having trouble reproducing the problem. Here’s my scala-cli script:

//> using dep com.softwaremill.sttp.client3::core:3.11.0

import sttp.client3._

object Test extends App {
  val syncBackend = HttpClientSyncBackend()
  val response = basicRequest
    .head(
      uri"https://dts.podtrac.com/redirect.mp3/rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3"
    )
    .send(syncBackend)

  println(response)
}

and running it:

% scala-cli test.scala 
Compiling project (Scala 3.4.2, JVM (21))
Compiled project (Scala 3.4.2, JVM (21))
Response(Right(),200,,List(strict-transport-security: max-age=300, x-served-by: cache-sjc10067-SJC, cache-sjc1000138-SJC, cache-fra-etou8220098-FRA, x-content-type-options: nosniff, x-runtime: 0.027283, referrer-policy: strict-origin-when-cross-origin, date: Thu, 15 May 2025 08:28:01 GMT, x-permitted-cross-domain-policies: none, accept-ranges: bytes, vary: Accept, Accept-Encoding, Accept-Language, Authorization, Origin, x-request-id: 43f319e5-58e2-4af4-a05b-9c513998cb6a, x-cache: MISS, MISS, MISS, x-cache-hits: 0, 0, 0, x-xss-protection: 1; mode=block, server: Fastly, cache-control: no-cache, x-download-options: noopen, content-type: audio/mpeg, via: 1.1 haproxy, 1.1 varnish, 1.1 varnish, 1.1 varnish, x-frame-options: DENY, x-timer: S1747297682.711358,VS0,VE207, :status: 200),List(Response((),302,,List(expires: -1, cache-control: no-cache, no-store, must-revalidate, location: https://rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3, date: Thu, 15 May 2025 08:28:01 GMT, :status: 302, pragma: no-cache),List(),RequestMetadata(HEAD,https://dts.podtrac.com/redirect.mp3/rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3,Vector(Accept-Encoding: gzip, deflate)))),RequestMetadata(HEAD,https://rss.art19.com/episodes/9cb995c1-8587-4626-8444-162ab50137be.mp3?rss_browser=BAhJIglpdG1zBjoGRVQ%3D--1ad3f3f0406ff401463d323535582d372dd266b3,Vector(Accept-Encoding: gzip, deflate)))

Good to hear from you Adam, I appreciate the prompt reply! That’s right, I haven’t used the API for a while and remembered (incorrectly) that .history also includes the final response. Thank you for clarifying