> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://rivet.chrisboulton.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://rivet.chrisboulton.com/_mcp/server.

# Conversion, errors, and sensitivity

> Signatures, behavior, examples, and Rivet compatibility boundaries.

Conversions are explicit. Resource fields and external inputs retain their strict declared types.

| Function               | Result and rules                                                                                                           |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| `tostring(value)`      | String from a string, finite number, or boolean; null stays null.                                                          |
| `tonumber(value)`      | Finite number from a number or numeric string; integer spelling preserves integer precision; null stays null.              |
| `tobool(value)`        | Boolean from a boolean or exactly true/false string; null stays null.                                                      |
| `tolist(value)`        | List from list or set, with primitive element unification; null stays null.                                                |
| `tomap(value)`         | Map with primitive value unification; null stays null.                                                                     |
| `toset(value)`         | Deterministically sorted and deduplicated set from list or set with primitive unification; null stays null.                |
| `convert(value, type)` | Recursive conversion using the constraints below.                                                                          |
| `try(expressions...)`  | Evaluate left to right until one succeeds; all failures produce a safe error. Failed attempts retain observed annotations. |
| `can(expression)`      | Boolean indicating whether evaluation succeeds; attempted dependencies and sensitivity are preserved.                      |
| `sensitive(value)`     | Recursively mark the value, elements, and keys sensitive; retain dependencies.                                             |
| `nonsensitive(value)`  | Explicitly remove sensitivity recursively; retain dependencies.                                                            |
| `issensitive(value)`   | Public boolean reporting sensitivity; retain dependencies without revealing the value.                                     |

`tolist`, `tomap`, `toset`, and `coalesce` unify primitive elements: when a string is present, numbers and booleans become strings; incompatible mixtures fail. Nested collection shapes keep Rivet's existing behavior rather than implementing Terraform's complete type unification.

`convert(value, type)` accepts `string`, `number`, `bool`, `any`, `list(T)`, `set(T)`, `map(T)`, `tuple([T, ...])`, and `object({ field = T, ... })`. Object conversion discards extra attributes, rejects missing required attributes, and accepts `optional(T)` or `optional(T, default)`. Constraints are validated even for empty or null inputs; optional defaults evaluate and convert once per constraint before reuse. These constraints belong to `convert`; `any` and two-argument optional defaults do not extend variable and output declarations.

`try` and `can` take explicit unevaluated expressions and do not accept final argument expansion. Ordinary functions evaluate arguments eagerly: `lookup(map, key, fallback)` is not a lazy fallback. Both error helpers conservatively retain dependencies and sensitivity from attempted subexpressions, including failed attempts. A conditional evaluates only its selected branch.

`nonsensitive` is an explicit declassification operation. Resource `meta.sensitive = false` and output policies do not clear inherited sensitivity; password-hash resource fields reassert their intrinsic sensitivity. RSA decryption marks its result sensitive initially, and explicit nonsensitive can remove that value annotation. SOPS-supplied variables are automatically sensitive. Bundles can contain plaintext values regardless of redaction.

## Example

```hcl
locals {
  private = sensitive("example-value")
  conversions = {
    text = tostring(8080)
    number = tonumber("8080")
    boolean = tobool("true")
    list = tolist(toset(["ops", "app"]))
    map = tomap({ app = 1, web = "2" })
    set = toset(["app", "app", "ops"])
    object = convert({ port = "8080", extra = "discarded" }, object({ port = number, enabled = optional(bool, true) }))
    fallback = try(tonumber("invalid"), 8080)
    valid = can(tonumber("8080"))
    marked = issensitive(local.private)
    public = nonsensitive(local.private)
  }
}
output "conversions" {
  type  = string
  value = jsonencode(local.conversions)
}
```

All calls obey the [function limits and annotation rules](/language/functions).