Passing Error Information to User through description_placeholders

I’ve seen that description_placeholders in FlowResult is a dictionary with signature [str, str] and the docs suggest that it’s for ‘detailed information about the step’. In code data from async_show_form() is injected back to the caller through this parameter. Is this data supposed to be shown to the user somehow or is it more for internal consumption?

If the earlier, how to use it to give the user a more detailed error message when adding the integration?

When _create_entry() fails I’m calling async_show_form() again passing it the extended error message with the error key of description_placeholders. However, I don’t see the error message showing in the frontend.

This is the outline of how I’m doing it:

async def _create_entry(description_placeholders):
  try:
    # setup the device
  except Exception as error:
    description_placeholders["error"] = str(error.args)
    return None
    
 
async def async_step_user():
  placeholders: dict[str, str] = {}
  
  result = self._create_entry(
      description_placeholders=placeholders
  )
  if result:
    return result
  
  return self.async_show_form(
    description_placeholders=placeholders
  )

To see errors in the form, you have to pass the errors parameter to async_show_form. Example below from integration i support.

async def async_step_user(self, user_input=None):
        """
        Handle a Wiser Heat Hub config flow start.

        Manage device specific parameters.
        """
        errors = {}
        if user_input is not None:
            try:
                validated = await validate_input(self.hass, user_input)
            except WiserHubAuthenticationError:
                errors["base"] = "auth_failure"
            except WiserHubConnectionError:
                errors["base"] = "timeout_error"
            except (
                WiserHubRESTError,
                RuntimeError,
            ) as ex:
                errors["base"] = "unknown"
                _LOGGER.debug(ex)

            if "base" not in errors:
                await self.async_set_unique_id(validated["unique_id"])
                self._abort_if_unique_id_configured()

                # Add hub name to config
                user_input[CONF_NAME] = validated["title"]

                return self.async_create_entry(
                    title=validated["title"], data=user_input
                )

        return self.async_show_form(
            step_id="user",
            data_schema=self.discovery_info or DATA_SCHEMA,
            errors=errors,
        )

Thanks, Mark. I’m passing a basic error message using errors as you do, but one of the reviewers of my PR suggested to include in description_placeholders a more detailed error description for the user.

Oh, ok now I understand. In the strings.json you need to have the param name as part of the text description in curly brackets. Then the value passed in description_placeholders will replace that.

Ie.

In strings.json

"error": {
        "cannot_connect": "Failed to connect. {error_detail}"
}

And your code to set it would be

description_placeholders["error_detail"] = str(error.args)

It works. Before I only saw the basic error:

image

Now it adds the exception: