Conversion, errors, and sensitivity
Conversions are explicit. Resource fields and external inputs retain their strict declared types.
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
All calls obey the function limits and annotation rules.