Terraform
Returning Function Errors
Providers use FuncError
to
surface a practitioner-facing error generated during execution of provider-defined functions. These errors are
returned from Terraform CLI at the end of command output:
$ terraform plan
# ... other plan output ...
╷
│ Error: Error in function call
│
│ on example.tf line #:
│ #: source configuration line
│
│ Call to function "{FUNCTION}" failed: {TEXT}.
$ terraform plan
# ... other plan output ...
╷
│ Error: Invalid function argument
│
│ on example.tf line #:
│ #: source configuration line
│
│ Invalid value for "{PARAMETER_NAME}" parameter: {TEXT}.
In the framework, you may encounter them in response structs or as returns from provider-defined function execution.:
func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
This is the most common form for FuncError
: a single error whose text
is the concatenated error text from one or more errors. This approach allows
your provider to inform practitioners about all relevant errors at the same
time, allowing practitioners to fix their configuration or environment more
quickly. You should only concatenate a FuncError
and never replace or
remove information it.
The next section will detail the concepts and typical behaviors of
function error, while the final section will outline the typical methods for
working with function error, using functionality from the available
function
package.
Function Error Concepts
Text
Text
is a practitioner-oriented description of the problem. This should
contain sufficient detail to provide both general and more specific information
regarding the issue. For example "Error executing function: foo can only contain
letters, numbers, and digits."
FunctionArgument
FunctionArgument
is a zero-based, int64 value that identifies the specific
function argument position that caused the error. Only errors that pertain
to a function argument will include this information.
Working With Existing Function Errors
ConcatFuncErrors
When receiving function.FuncError
from a function or method, such as
Run()
, these should typically be concatenated with the
response function error for the method. This can be accomplished with the
ConcatFuncErrors(in ...*FuncError)
method.
For example:
func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
var boolArg bool
var stringArg string
resp.Error = function.ConcatFuncErrors(resp.Error, req.Arguments.Get(ctx, &boolArg, &stringArg))
// ... other logic ...
}
This method automatically ignores nil
function errors.
Creating Function Errors
To craft the message of a function error, it is recommended to use sufficient detail to convey both the cause of the error and as much contextual, troubleshooting, and next action information as possible. These details can use newlines for easier readability where necessary.
NewFuncError
When creating function errors where a function.FunctionError
is already available,
such as within a response type, the ConcatFuncErrors(in ...*FuncError)
function
can be used with the NewFuncError(text string)
function to concatenate a new
function error.
For example:
func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
// ... prior logic ...
val, err := // operation that may return an error
if err != nil {
resp.Error = ConcatFuncErrors(resp.Error, function.NewFuncError("Error performing operation: " + err.Error()))
return
}
// ... further logic ...
}
NewArgumentFuncError
When creating function errors that affect only a single function argument, the NewArgumentFuncError(functionArgument int, msg string)
function
can be used in conjunction with the ConcatFuncErrors(in ...*FuncError)
function. This provides additional context to practitioners, such as showing the specific line(s) and value(s) of configuration where possible.
For example:
func (f ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
// ... other logic ...
// Add function error associated with first function argument position
resp.Error = function.ConcatFuncErrors(resp.Error, function.NewArgumentFuncError(0, "Example Error Summary: Example Error Detail"))
// ... other logic ...
}
FuncErrorFromDiags
A function error is created from diagnostics by using the FuncErrorFromDiags(context.Context, diag.Diagnostics)
function. The function error will contain the concatenated summary and details of error-level
diagnostics.
Note: The FuncErrorFromDiags(context.Context, diag.Diagnostics)
function does not include warning-level diagnostics in the function error. Warning-level diagnostics are logged instead.
For example:
func (f *ExampleFunction) Run(ctx context.Context, req function.RunRequest, resp *function.RunResponse) {
// ... other logic ...
_, diags := // operation that may return diagnostics
resp.Error = function.ConcatFuncErrors(resp.Error, function.FuncErrorFromDiags(ctx, diags))
}