Tratamento de erros

Nota

O comportamento que este artigo descreve está disponível apenas quando a versão prévia do recurso Gerenciamento de erros no nível da fórmula em Configurações>Próximos recursos>Versão prévia está ativado. Mais Informações: Como controlar quais recursos são habilitados

Erros acontecem. As redes ficam inativas, o armazenamento fica cheio, valores inesperados fluem. É importante que sua lógica continue funcionando adequadamente diante de possíveis problemas.

Por padrão, os erros fluem pelas fórmulas de um aplicativo e são relatados ao usuário final do aplicativo. Dessa forma, o usuário final sabe que algo inesperado aconteceu, pode corrigir o problema sozinho com uma entrada diferente ou pode relatar o problema ao proprietário do aplicativo.

Como criador de app, você pode controlar os erros em seu aplicativo:

  • Detecção e tratamento de um erro. Se houver uma chance de ocorrer um erro, as fórmulas do aplicativo poderão ser gravadas para detectar a condição de erro e repetir a operação. O usuário final não precisa se preocupar com a ocorrência de um erro porque o fabricante contou com essa possibilidade. Isso é feito com as funções IfError, IsError e IsErrorOrBlank em uma fórmula.
  • Relato de um erro. Se um erro não for tratado na fórmula em que foi encontrado, o erro será adicionado ao manipulador App.OnError. Aqui, o erro não pode mais ser substituído, pois já ocorreu e faz parte dos cálculos da fórmula. Mas você pode usar App.OnError para controlar como o erro é relatado ao usuário final, incluindo a supressão do relatório de erros. App.OnError também fornece um ponto de redução comum para relatórios de erros em todo o aplicativo.
  • Criação e relançamento de um erro. Por fim, você pode detectar uma condição de erro com sua própria lógica, uma condição específica do seu aplicativo. Use a função Error para criar e relatar erros personalizados. A função Error também é usada para relançar um error após ser interrogado em IfError ou App.OnError.

Introdução

Vamos começar com um exemplo simples.

  1. Crie uma nova tela em um aplicativo de Tela do Power Apps.
  2. Insira um controle TextInput. O padrão será o nome TextInput1.
  3. Insira um controle Label.
  4. Defina a propriedade Text do controle Label para a fórmula .
1/Value( TextInput1.Text )

Banner de erro exibido com

Ocorreu um erro porque o texto padrão de um controle TextInput é "Text input", que não pode ser convertido em um número. Por padrão, isso é bom: o usuário final receberá uma notificação de que algo não está funcionando conforme o esperado no aplicativo.

Obviamente, não desejamos que um erro apareça para o usuário toda vez que ele inicia este aplicativo. É provável que "Text input" não seja o padrão certo para a caixa de entrada de texto. Para corrigir isso, vamos alterar a propriedade Default do controle TextInput para:

Blank()

Banner de erro exibido com

Mas, agora temos um erro diferente. Operações matemáticas com a função blank, como divisão, forçarão o valor em branco a ser zerado. Agora isso está causando um erro de divisão por zero. Para corrigir isso, precisamos decidir qual é o comportamento apropriado para esta situação neste aplicativo. A resposta pode ser mostrar blank quando a entrada de texto estiver em branco. Podemos fazer isso agrupando nossa fórmula com a função IfError:

IfError( 1/Value( TextInput1.Text ), Blank() )

Nenhum banner de erro exibido, um erro devido a um valor em branco foi substituído por um em branco

Agora o erro foi substituído por um valor válido e a faixa de erros desapareceu. Mas, podemos ter exagerado: o IfError que usamos trata de todos os erros, incluindo a digitação de um valor incorreto como "hello". Podemos resolver isso ajustando nosso IfError para lidar apenas com a divisão por zero e relançar todos os outros erros:

IfError( 1/Value( TextInput1.Text ), 
         If( FirstError.Kind = ErrorKind.Div0, Blank(), Error( FirstError ) ) )

Nenhum banner de erro exibido, um erro devido especificamente à divisão por zero foi substituído por um espaço em branco; caso contrário, o erro é lançado novamente

Vamos executar nosso aplicativo e testar alguns valores diferentes.

Sem valor, como quando o aplicativo inicia, não há resposta exibida, pois o valor padrão é em branco, mas nenhum erro exibido como IfError substitui o erro de divisão por zero.

Nenhuma resposta exibida e nenhum banner de erro

Se digitarmos um 4, obteremos o resultado esperado de 0,25:

0,25 exibido e nenhum banner de erro

Se digitarmos algo ilegal, como hello, receberemos uma faixa de erros:

Nenhum valor exibido e banner de erro mostrado para a incapacidade de converter

Este é um exemplo introdutório simples. O tratamento de erros pode ser feito de várias maneiras distintas, dependendo das necessidades do aplicativo:

  1. Em vez de uma faixa de erros, poderíamos ter mostrado "#Error" no controle de rótulo com a fórmula. Para manter os tipos das substituições compatíveis com o primeiro argumento para IfError, precisamos converter explicitamente o resultado numérico em uma cadeia de texto com a função Text.
    IfError( Text( 1/Value( TextInput1.Text ) ), 
             If( FirstError.Kind = ErrorKind.Div0, Blank(), "#Error" )
    
    Nenhum banner de erro e, em vez disso, #Error é mostrado como resultado
  2. Em vez de agrupar essa instância específica com IfError, poderíamos ter escrito um manipulador App.OnError centralizado. Não podemos substituir a cadeia mostrada por "#Error" porque o erro já ocorreu e App.OnError é fornecido apenas para relatórios de controle.
    If( FirstError.Kind <> ErrorKind.Div0, Error( FirstError ) )
    

Propagação de erros

Os erros fluem pelas fórmulas da mesma forma que no Excel. Por exemplo, no Excel, se a célula A1 tiver a fórmula =1/0, A1 exibirá o valor do erro #DIV0!:

Planilha Excel com A1=1/0 e #DIV/0! mostrado na célula

Se a célula A2 referir-se a A1 com uma fórmula como =A1*2, o erro também se propagará por essa fórmula:

Planilha Excel com A2=A1*2 e #DIV/0! mostrado na célula

O erro substitui o valor que teria sido calculado de outra forma. Não há resultado para a multiplicação na célula A2, apenas o erro da divisão em A1.

O Power Fx funciona da mesma forma. Em geral, se um erro for fornecido como um argumento para uma função ou operador, a operação não ocorrerá e o erro de entrada fluirá como resultado da operação. Por exemplo, Mid( Text( 1/0 ), 1, 1 ) retornará um erro de Divisão por Zero, pois o erro mais interno passa pelas funções Text e Mid:

Banner de erro mostrando operação inválida: divisão por zero

Em geral, os erros não fluem pelas propriedades de controle do Power Apps. Vamos estender o exemplo anterior com um controle adicional que exibe se a propriedade Text do primeiro rótulo é um estado de erro:

Nenhum erro mostrado no segundo controle de rótulo

Não há problemas se os erros não se propagarem por um controle porque o sistema observará erros na entrada de todas as propriedades do controle. O erro não será perdido.

A maioria das funções e operadores seguem a regra "entrada de erro, saída de erro", mas há exceções. As funções IsError, IsErrorOrBlank e IfError são criadas para trabalhar com erros; portanto, elas podem não retornar um erro, mesmo que um seja passado para elas.

Observação de erros

Os erros não são observados até que seu valor seja usado.

Como resultado, as funções If e Select também poderão não retornar um erro se um for passado. Considere a fórmula If( false, 1/0, 3 ). Há um erro de divisão por zero presente nesta fórmula, mas como o If não ocupa essa ramificação por causa do false, o Power Fx e o Power Apps não relatarão um erro:

Nenhum banner de erro mostrado com a função If na propriedade Text do rótulo

Usar a função Set com um erro não relatará um erro no ponto em que o erro é colocado na variável. Por exemplo, no Power Apps, existe uma fórmula em App.OnStart que insere um erro de divisão por zero na variável x:

Nenhum banner de erro mostrado com chamada de função Set em App.OnStart

Nenhum erro é relatado porque x não é referenciado. No entanto, no momento em que adicionamos um controle de rótulo e definimos a propriedade Text como x, o erro é exibido:

Banner de erro mostrado com controle de rótulo referenciando a variável x

Você pode observar erros em uma fórmula com as funções IfError, IsError e IsErrorOrBlank. Com essas funções, você pode retornar um valor alternativo, executar uma ação alternativa ou modificar o erro antes que ele seja observado e relatado.

Relato de erros

Ao encontrar um erro, a próxima etapa é relatá-lo ao usuário final.

Diferente do Excel, nem sempre há um local conveniente para mostrar um resultado de erro, pois o resultado de uma fórmula pode direcionar uma propriedade como as coordenadas X e Y de um controle para o qual não há local conveniente para mostrar um texto. Cada host do Power Fx controla como os erros são exibidos ao usuário final e qual é o controle do criador sobre esse processo. No Power Apps, uma faixa de erros é mostrada e o App.OnError é usado para controlar como o erro é relatado.

É importante notar que o App.OnError não pode substituir o erro da mesma forma que o IfError. No ponto em que App.OnError é executado, o erro já ocorreu e o resultado foi propagado por meio de outras fórmulas. App.OnError apenas controla como o erro é relatado ao usuário final e fornece um gancho para o criador registrar o erro, se desejado.

As variáveis de escopo FirstError e AllErrors fornecem informações de contexto sobre o(s) erro(s). Isso fornece informações sobre o tipo de erro, sua origem e onde foi observado.

Interrupção após um erro

As fórmulas de comportamento dão suporte à ação, modificando bancos de dados e alterando o estado. Essas fórmulas permitem que mais de uma ação seja executada em uma sequência usando o ; operador de encadeamento (ou ;; dependendo da localidade).

Neste caso, por exemplo, o controle de grade mostra o que está na tabela T. Cada seleção de botão altera o estado nesta tabela com duas chamadas Patch:

Animação mostrando os dois registros da tabela T sendo atualizados com números aleatórios a cada clique do botão

Em uma fórmula de comportamento encadeado, as ações não param após o primeiro erro. Vamos modificar nosso exemplo para passar um número de índice inválido na primeira chamada Patch . O segundo Patch continua, apesar do erro anterior. O primeiro erro é relatado ao usuário final, e mostrado como um erro no Studio no controle:

Animação mostrando apenas o segundo registro da tabela T sendo atualizado com números aleatórios após cada clique no botão, o primeiro registro resultando em erro

IfError pode ser usado para interromper a execução após um erro. Semelhante à função If, o terceiro argumento dessa função fornece um local para inserir ações que deverão ser executadas apenas se não houver erro:

Animação mostrando nenhuma alteração em nenhum dos registros da tabela T, porque o IfError está impedindo a conclusão da segunda operação após um erro

Se um erro for encontrado durante uma das iterações de ForAll, as demais iterações não serão interrompidas. ForAll foi criado para executar cada iteração de forma independente, permitindo a execução paralela. Quando o ForAll estiver concluído, um erro será retornado, contendo todos os erros encontrados (examinando AllErrors em IfError ou App.OnError).

Por exemplo, a fórmula a seguir resultará em ForAll retornando dois erros (para a divisão por zero para Value de 0, duas vezes) e Collection terá três registros (para quando Value não for 0): [1, 2, 3].

Clear( Collection ); 
ForAll( [1,0,2,0,3], If( 1/Value > 0, Collect( Collection, Value ) ) );

Trabalhar com vários erros

Como uma fórmula de comportamento pode executar mais de uma ação, ela também pode encontrar mais de um erro.

Por padrão, o primeiro erro é relatado ao usuário final. Neste exemplo, ambas as chamadas Patch falharão, a segunda com um erro de divisão por zero. Apenas o primeiro erro (sobre o índice) é mostrado ao usuário:

Primeiro erro de índice exibido em um banner de erro, o segundo erro não é relatado

A função IfError e App.OnError podem acessar todos os erros encontrados com a variável de escopo AllErrors . Nesse caso, podemos definir isso como uma variável global e examinar os dois erros encontrados. Eles aparecem na tabela na mesma ordem em que foram encontrados:

Captura dos erros na variável global PatchErrors onde podemos ver que ambos os erros estão presentes

Vários erros também podem ser retornados em fórmulas sem comportamento. Por exemplo, usar a função Patch com um lote de registros para atualizar pode retornar vários erros, um para cada registro com falha.

Erros em tabelas

Como vimos anteriormente, os erros podem ser armazenados em variáveis. Erros também podem ser incluídos em estruturas de dados, como tabelas. Isso é importante para que um erro em um registro não invalide a tabela inteira.

Por exemplo, considere este controle de tabela de dados no Power Apps:

Tabela de dados mostrando um erro para o campo Reciprocal para uma entrada de 0, que resulta em um erro de divisão por zero

O cálculo em AddColumns encontrou um erro de divisão por zero para um dos valores. Para esse registro, a coluna Reciprocal tem um valor de erro (divisão por zero), mas os outros registros não e não há problema. IsError( Index( output, 2 ) ) retorna falso e IsError( Index( output, 2 ).Value ) retorna verdadeiro.

Se ocorrer um erro ao filtrar uma tabela, o registro inteiro será um erro, mas ainda será retornado no resultado para que o usuário final saiba que há um problema.

Imagine este exemplo. Aqui, a tabela original não tem erros, mas o ato de filtrar gera um erro sempre que Value é igual a 0:

Tabela de dados mostrando erros para dois registros que não puderam ser processados pelos critérios de filtro

Os valores -5 e -3 são devidamente filtrados. Os valores 0 resultam em um erro no processamento do filtro e, portanto, não fica claro se o registro deve ser incluído ou não no resultado. Para maximizar a transparência para os usuários finais e ajudar os criadores a depurar, incluímos um registro de erro em vez do original. Nesse caso, IsError( Index( output, 2 ) ) retorna true.

Erros na fonte de dados

As funções que modificam dados em fontes de dados, como Patch, Collect, Remove, RemoveIf, Update, UpdateIf e SubmitForm relatam erros de duas maneiras:

  • Cada uma dessas funções retornará um valor de erro como resultado da operação. Erros podem ser detectados com IsError e substituídos ou suprimidos com IfError e App.OnError como de costume.
  • Após a operação, a função Errors também retornará os erros das operações anteriores. Isso pode ser útil para exibir a mensagem de erro em uma tela de formulário sem precisar capturar o erro em uma variável de estado.

Por exemplo, esta fórmula verificará um erro de Collect e exibirá uma mensagem de erro personalizada:

IfError( Collect( Names, { Name: "duplicate" } ),
         Notify( $"OOPS: { FirstError.Message }", NotificationType.Warning ) )

A função Errors também retorna informações sobre erros anteriores durante operações de tempo de execução. Isso pode ser útil para exibir um erro em uma tela de formulário, sem precisar capturar o erro em uma variável de estado.

Relançar erros

Às vezes, alguns erros potenciais são esperados e podem ser ignorados com segurança. No IfError e no App.OnError, se for detectado um erro que deva ser passado para o próximo manipulador superior, ele poderá ser relançado com Error( AllErrors ).

Criar seus próprios erros

Você também pode criar seus próprios erros com a função Error.

Se estiver criando seus próprios erros, será recomendável usar valores acima de 1.000 para evitar possíveis conflitos com futuros valores de erro do sistema.

Valores de enumeração ErrorKind

Enumeração ErrorKind Valor Description
AnalysisError 18 Erro do sistema. Ocorreu um problema com a análise do compilador.
BadLanguageCode 14 Um código de idioma inválido ou não reconhecido foi usado.
BadRegex 15 Expressão regular inválida. Verifique a sintaxe usada com as funções IsMatch, Match ou MatchAll.
Conflito 6 O registro atualizado já foi alterado na fonte e o conflito precisa ser resolvido. Uma solução comum é salvar as alterações locais, atualizar o registro e reaplicar as alterações.
ConstraintViolated 8 O registro não passou em uma verificação de restrição no servidor.
CreatePermission 3 O usuário não tem permissão para criar registros para a fonte de dados. Por exemplo, a função Collect foi chamada.
DeletePermissions 5 O usuário não tem permissão para excluir registros para a fonte de dados. Por exemplo, a função Remove foi chamada.
Div0 13 Divisão por zero.
EditPermissions 4 O usuário não tem permissão para criar registros para a fonte de dados. Por exemplo, a função Patch foi chamada.
GeneratedValue 9 Um valor foi passado de forma errada ao servidor para um campo que é calculado automaticamente pelo servidor.
InvalidFunctionUsage 16 Uso inválido de uma função. Em geral, um ou mais argumentos da função estão incorretos ou são usados de forma inválida.
FileNotFound 17 Não foi possível localizar o armazenamento SaveData.
InsufficientMemory 21 Não há memória ou armazenamento suficiente no dispositivo para a operação.
InvalidArgument 25 Um argumento inválido foi passado para uma função.
Internos 26 Erro do sistema. Houve um problema interno com uma das funções.
MissingRequired 2 Um campo obrigatório de um registro estava ausente.
Rede 23 Houve um problema com as comunicações da rede.
Nenhum 0 Erro do sistema. Não há erro.
Não Aplicável 27 Não há valor disponível. Útil para diferenciar um valor em branco que pode ser tratado como zero em cálculos numéricos de valores em branco que deverão ser sinalizados como um problema potencial se o valor for usado.
NotFound 7 Não foi possível encontrar o registro. Por exemplo, o registro a ser modificado na função Patch.
NotSupported 20 Operação sem suporte para este player ou dispositivo.
Numérico 24 Uma função numérica foi usada de forma imprópria. Por exemplo, substitua Sqrt por -1.
QuoteExceeded 22 Cota de armazenamento excedida.
ReadOnlyValue 10 Essa coluna é somente leitura e não pode ser modificada.
ReadPermission 19 O usuário não tem permissão para ler registros para a fonte de dados.
Sincronizar 0 Um erro foi relatado pela fonte de dados. Verifique a coluna Mensagem para obter mais informações.
Desconhecido 12 Ocorreu um erro, mas de um tipo desconhecido.
Validação 11 O registro não passou em uma verificação de validação.