For AI agents: the complete documentation index is available at /hclapi/llms.txt, the full documentation bundle is available at /hclapi/llms-full.txt, and this page is available as Markdown at /hclapi/docs/manifest/functions/system/problem.md.

problem

Constructs an RFC 9457 compliant Problem Details error payload. Supports both positional shorthand for common errors and map syntax for structured validation errors and custom metadata extensions.

Signatures

# 1. Positional shorthand (simple errors)
problem(status: int, detail: string, custom_type: string...) -> map

# 2. Object map syntax (rich errors with extensions)
problem(config: map) -> map

Parameters

Positional syntax

ParameterTypeRequiredDescription
statusintyesHTTP status code (e.g. 400, 404, 409, 422, 500)
detailstringyesHuman-readable explanation specific to this occurrence
custom_typestringnoCustom problem type URI or slug (defaults to slugified HTTP title)

Object map syntax

FieldTypeRequiredDescription
statusintyesHTTP status code
detailstringyesHuman-readable explanation
titlestringnoCustom title (defaults to standard http.StatusText)
typestringnoCustom type URI or slug (defaults to URN or problem.type_prefix)
instancestringnoRequest path identifier (defaults to current route path)
*anynoAny additional key-value pairs are preserved as RFC 9457 extensions

Automatic field derivation

To minimize boilerplate in manifests, problem() automatically derives missing fields:

  1. Title: If title is omitted, the engine uses the canonical HTTP status text for status (e.g. 404 -> "Not Found", 409 -> "Conflict").
  2. Type URI: If type is omitted, the title is slugified and appended to the configured URI scheme:
    • Default: "urn:hclapi:error:<slug>" (e.g. "urn:hclapi:error:not-found").
    • If problem.type_prefix is set in server {}: problem.type_prefix + "<slug>" (e.g. "https://docs.example.com/errors/not-found").
  3. Instance: Defaults to the current request's URL path (ctx.request.path).

Examples

1. Simple 404 not found response (Positional)

endpoint "GET /api/v1/users/{id}" {
  pipeline {
    sql "find_user" {
      connection = connection.postgres.main
      query      = "SELECT id, name FROM users WHERE id = @id"
      args       = { id = ctx.request.path.id }
    }

    respond {
      condition = steps.find_user.rows_affected == 0
      status    = 404
      body      = problem(404, "User with ID ${ctx.request.path.id} not found")
    }

    respond {
      status = 200
      body   = steps.find_user.row
    }
  }
}

Serialized output:

{
  "type": "urn:hclapi:error:not-found",
  "title": "Not Found",
  "status": 404,
  "detail": "User with ID 42 not found",
  "instance": "/api/v1/users/42"
}

2. Database constraint collision with custom slug (Positional)

sql "insert_user" {
  connection = connection.postgres.main
  query      = "INSERT INTO users (email) VALUES (@email)"
  args       = { email = ctx.request.body.email }

  catch "23505" {
    status = 409
    body   = problem(409, "Email address is already registered", "email-collision")
  }
}

Serialized output:

{
  "type": "urn:hclapi:error:email-collision",
  "title": "Conflict",
  "status": 409,
  "detail": "Email address is already registered",
  "instance": "/api/v1/users"
}

3. Validation failure with RFC 9457 extensions (Map syntax)

respond {
  condition = ctx.request.body.age < 18
  status    = 422
  body = problem({
    status     = 422
    title      = "Unprocessable Entity"
    detail     = "User must be at least 18 years old"
    error_code = "AGE_RESTRICTION"
    invalid_params = [
      { name = "age", reason = "must be greater than or equal to 18" }
    ]
  })
}

Serialized output:

{
  "type": "urn:hclapi:error:unprocessable-entity",
  "title": "Unprocessable Entity",
  "status": 422,
  "detail": "User must be at least 18 years old",
  "instance": "/api/v1/users",
  "error_code": "AGE_RESTRICTION",
  "invalid_params": [
    {
      "name": "age",
      "reason": "must be greater than or equal to 18"
    }
  ]
}

Errors

  • Fails with an evaluation error if status is not an integer or if required arguments are missing.
  • Fails with an evaluation error if a single argument is passed that is not a map or number.