# Missing header I get 415

**URL:** <https://softwaremill.community/t/missing-header-i-get-415/365>\
**Category:** tapir\
**Created:** [February 19, 2024, 5:25pm UTC](https://softwaremill.community/t/missing-header-i-get-415/365 "2024-02-19T17:25:31Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![M\_Perez](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/m_perez/32/235_2.png) [@M\_Perez](https://softwaremill.community/u/M_Perez)\
**Post date:** [February 19, 2024, 5:25pm UTC](https://softwaremill.community/t/missing-header-i-get-415/365/1 "2024-02-19T17:25:31Z")

</div>

```
endpoint.post
  .in("any")
  .in(header(Header.contentType(MediaType.ApplicationXWwwFormUrlencoded)))

```

my endpoint looks like this, but when I make a request and I don’t specify the header I want to receive a 400 not a 415 as it does now, how could I map it?

I am using Http4sServerInterpreter

Thanks

---

<div class="post-metadata">

**Author:** ![kciesielski](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/kciesielski/32/133_2.png) [@kciesielski](https://softwaremill.community/u/kciesielski)\
**Post date:** [February 20, 2024, 11:34am UTC](https://softwaremill.community/t/missing-header-i-get-415/365/3 "2024-02-20T11:34:59Z")

</div>

You can use a custom `DecodeFailureHandler`, here’s a scala-cli example:

```auto
//> using lib "com.softwaremill.sttp.tapir::tapir-core:1.9.9"
//> using lib "com.softwaremill.sttp.tapir::tapir-http4s-server:1.9.9"
//> using lib "org.http4s::http4s-blaze-server:0.23.16"
//> using lib "org.http4s::http4s-dsl:0.23.25"

import cats.effect._
import org.http4s._
import org.http4s.dsl.io._
import org.http4s.server.blaze._
import org.http4s.implicits._
import scala.concurrent.ExecutionContext.{global => ecGlobal}
import sttp.tapir._
import sttp.tapir.server.http4s.Http4sServerInterpreter
import cats.effect.unsafe.implicits.global
import sttp.model.Header
import sttp.model.MediaType
import sttp.tapir.server.http4s.Http4sServerOptions
import sttp.tapir.server.interceptor.decodefailure.DecodeFailureHandler
import sttp.tapir.server.interceptor.DecodeFailureContext
import sttp.monad.MonadError
import sttp.tapir.server.model.ValuedEndpointOutput
import sttp.tapir.server.interceptor.decodefailure.DefaultDecodeFailureHandler
import sttp.tapir.DecodeResult.Mismatch
import sttp.tapir.DecodeResult.InvalidValue
import sttp.model.StatusCode
import sttp.tapir.EndpointIO.FixedHeader
import sttp.model.HeaderNames

val helloEndpoint = endpoint.post
  .in("hello")
  .in(header(Header.contentType(MediaType.ApplicationXWwwFormUrlencoded)))
  .out(stringBody)

//------------------------------------------------------------
val customDecodeFailureHandler: DecodeFailureHandler[IO] = new DecodeFailureHandler[IO] {
  val defaultHandler = DefaultDecodeFailureHandler[IO]
  override def apply(ctx: DecodeFailureContext)(implicit monad: MonadError[IO]): IO[Option[ValuedEndpointOutput[_]]] =
    ctx.failingInput match {
      case FixedHeader(Header(HeaderNames.ContentType, "application/x-www-form-urlencoded"), _, _) =>
        IO.pure(Some(ValuedEndpointOutput(statusCode.and(sttp.tapir.headers).and(stringBody), (StatusCode.BadRequest, List.empty, "Your bad request message"))))
      case other =>
        defaultHandler(ctx) 
    }
}
val options = Http4sServerOptions.customiseInterceptors[IO].decodeFailureHandler(customDecodeFailureHandler).options
//------------------------------------------------------------
val helloRoute = Http4sServerInterpreter[IO](options).toRoutes(helloEndpoint.serverLogic[IO](_ => IO(Right("Hello"))))
val httpApp: HttpApp[IO] = helloRoute.orNotFound
val server = BlazeServerBuilder[IO]
  .withExecutionContext(ecGlobal)
  .bindHttp(8080, "localhost")
  .withHttpApp(httpApp)
  .resource

def runServer: IO[Unit] = server.use(_ => IO.never)

def main(args: Array[String]): Unit = {
  runServer.unsafeRunSync()
}

```

Note that this handler will be applied gobally. If you want to limit it to certain endpoints and leave default handling in others, consider adding endpoint attributes to the condition.

---

<div class="post-metadata">

**Author:** ![adamw](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/adamw/32/28_2.png) [@adamw](https://softwaremill.community/u/adamw)\
**Post date:** [February 20, 2024, 3:28pm UTC](https://softwaremill.community/t/missing-header-i-get-415/365/4 "2024-02-20T15:28:48Z")

</div>

@kciesielski however … the [code](https://github.com/softwaremill/tapir/blob/abeb5d72e4e7a16c4da3830a59eb58862dfda69b/server/core/src/main/scala/sttp/tapir/server/interceptor/decodefailure/DecodeFailureHandler.scala#L121) only specified to return 415 when there’s a mismatch on the header values. If the header is missing (which I think should be represented as `DecodeResult.Missing`), then you would get a 400 I suppose?

@M_Perez are you sure you are **not** sending any `Content-Type` header in your request?

---

<div class="post-metadata">

**Author:** ![kciesielski](https://dub1.discourse-cdn.com/flex005/user_avatar/softwaremill.community/kciesielski/32/133_2.png) [@kciesielski](https://softwaremill.community/u/kciesielski)\
**Post date:** [February 20, 2024, 7:18pm UTC](https://softwaremill.community/t/missing-header-i-get-415/365/5 "2024-02-20T19:18:29Z")

</div>

@adamw hmm I checked that in the morning and I was pretty sure it also returned 415 for missing header (which made me wonder too), but now I repeated the test and I’m getting 400 with message:

```auto
Invalid value for: header Content-Type: application/x-www-form-urlencoded (missing)

```

as expected.

@M_Perez please check if your header is indeed missing. Maybe it’s set with unexpected value by the client library or some entities between client and server (proxies, etc).
