Lendo uma Mensagem de Erro do R
Um erro do R tem duas partes, e as duas são úteis:
Error in "10" + 5 : non-numeric argument to binary operator
Depois de Error in vem a chamada - o trecho exato de código que falhou ("10" + 5). Depois dos dois pontos vem a condição - o que deu errado (non-numeric argument to binary operator). Leia primeiro a chamada: ela diz onde, e muitas vezes você já consegue ver o problema ali mesmo, no código citado. Depois leia a condição para o porquê.
Dois hábitos separam quem depura rápido de quem sofre. Primeiro, leia de verdade a mensagem - as mensagens do R normalmente são precisas, só concisamente redigidas. Segundo, depure o primeiro erro, não o último: uma falha no começo de um script se propaga em uma pilha de erros "object not found" mais adiante, todos eles somem quando você corrige o original. O resto desta página é um decodificador para as mensagens que você mais vai encontrar, e depois as ferramentas para quando ler não basta.
Os Erros de Nome: Not Found
Error: object 'total' not found - o R pesquisou todo ambiente que conhece e nenhuma variável tem esse nome. Três causas cobrem quase todos os casos:
- Um erro de digitação, incluindo maiúsculas. O R diferencia maiúsculas de minúsculas:
Total,totaleTOTALsão três nomes distintos, e o R não vai adivinhar qual você quis dizer. - A linha que define não foi executada. Você escreveu
total <- sum(x)no script, mas nunca o executou nesta sessão - comum depois de reiniciar o R, quando o arquivo do script ainda mostra a linha mas a sessão nunca a viu. Rode o script desde o topo. - Ambiente errado. Variáveis criadas dentro de uma função vivem e morrem dentro daquela chamada. Usar uma delas fora da função é pedir algo que não existe mais - retorne o valor em vez disso.
Error: could not find function "read_excel" - mesma ideia, mas para um nome de função. Nove em cada dez vezes a função mora em um pacote que você instalou mas não carregou nesta sessão:
library(readxl) # the fix: loading is per-session, installing is per-machine
df <- read_excel("data.xlsx")
Se o próprio library(readxl) der erro, o pacote não está instalado - install.packages("readxl") primeiro. E se a função é do R base, você a digitou errado (lenght() é o rito de passagem de todo mundo).
Erros de Sintaxe: unexpected symbol
Error: unexpected symbol in "..." (e seus primos unexpected ')', unexpected string constant) significa que o R nem conseguiu analisar o código. A mensagem aponta para onde o R percebeu, que muitas vezes é depois de onde está o erro de fato. Os suspeitos de sempre:
mean(x na.rm = TRUE) # missing comma - should be mean(x, na.rm = TRUE)
name <- "Ada # unclosed quote - swallows the following lines
total <- sum(c(1, 2, 3) # unclosed paren - the error fires lines later
Quando a linha sinalizada parece inocente, o erro está quase sempre acima dela: uma aspa, um parêntese ou uma chave não fechados antes no arquivo. Um editor de código que destaca pares correspondentes encontra isso em segundos.
Erros de Tipo e de Indexação, Decodificados
non-numeric argument to binary operator - você fez conta com algo que não é um número, normalmente um número que chegou como texto (importações são a fonte clássica - uma coluna com uma palavra perdida entra como caractere, como visto em tipos de dados). A versão quebrada:
x <- "10"
x + 5
# Error in x + 5 : non-numeric argument to binary operator
E a correção - converta e depois calcule:
subscript out of bounds - você pediu a posição n em algo com menos de n elementos, usando [[ ]]:
scores <- list(ada = 92, grace = 88)
scores[[3]]
# Error in scores[[3]] : subscript out of bounds
Verifique length() antes de indexar ou, melhor, peça pelo nome (scores[["grace"]]) para que reordenar não te quebre. Repare na assimetria: colchetes simples são mais tolerantes - um [ ] fora do intervalo em um vetor retorna NA silenciosamente em vez de dar erro, o que troca um bug barulhento por um silencioso.
$ operator is invalid for atomic vectors - $ pertence a listas e data frames. Em um vetor nomeado, use colchetes:
([[ ]] dá o valor puro; [ ] mantém o nome anexado.) Esse erro muitas vezes significa que algo antes retornou um vetor quando você esperava um data frame - vá conferir essa suposição em vez de apenas trocar o operador.
argument is of length zero - um if () recebeu uma condição sem nada dentro, quase sempre um NULL que se infiltrou vindo de um elemento de lista ausente ou de uma função que não retornou nada:
threshold <- NULL
if (threshold > 5) print("big")
# Error in if (threshold > 5) print("big") : argument is of length zero
Proteja a verificação - e repare que && para de avaliar assim que a resposta é conhecida, então a comparação nunca roda sobre um NULL:
(Um erro relacionado, missing value where TRUE/FALSE needed, é a mesma falha com NA em vez de NULL - ali a proteção é is.na(), coberta em valores ausentes.)
replacement has length zero - a versão em atribuição da mesma doença: x[2] <- numeric(0) tenta preencher uma posição com zero valores. O que produziu o lado direito voltou vazio; depure isso, não a atribuição.
Avisos Não São Erros - e É Aí Que Mora o Perigo
Um erro interrompe a execução; um aviso não. O R termina o cálculo, te entrega um resultado e menciona suas ressalvas depois. Esse resultado às vezes está ótimo e às vezes está silenciosamente errado:
As duas linhas se completam. A primeira recicla o vetor mais curto e avisa longer object length is not a multiple of shorter object length - e reciclar um vetor de comprimento 2 contra um de comprimento 3 quase nunca é o que alguém quis. A segunda avisa NAs introduced by coercion e entrega um vetor com um buraco que fará todo mean() posterior retornar NA. Trate os dois avisos como bugs a investigar, não como ruído a ignorar. Em scripts você pode impor essa postura com options(warn = 2), que promove todo aviso a erro para que nada passe despercebido.
Tratando Falhas Com tryCatch()
Às vezes um erro é esperado - um arquivo corrompido em uma pasta com centenas, uma linha ruim - e você quer tratá-lo e seguir adiante em vez de morrer. tryCatch() envolve uma expressão arriscada com handlers:
A mecânica: se o bloco principal tem sucesso, seu valor é o resultado. Se der erro, o handler error = roda no lugar e o valor de retorno dele (aqui NA) vira o resultado - o script segue em frente. conditionMessage(e) recupera a mensagem original para registro. finally = roda em todo caso, com sucesso ou falha, e é ali que mora a limpeza, como fechar conexões - você pode vê-lo imprimir antes de cada resultado acima.
Existe também um handler warning = - tryCatch(as.numeric(x), warning = function(w) NA) captura o aviso de coerção da seção anterior em vez de deixá-lo passar. Um cuidado: um handler que retorna uma alternativa sem registrar nada é um jeito de esconder falhas, não de tratá-las. Sempre registre conditionMessage() - o seu eu futuro vai precisar.
Localizando a Falha: traceback(), browser() e o Print Honesto
Quando o erro vem do fundo de chamadas de função aninhadas, a mensagem sozinha não diz qual cadeia de chamadas te levou até ali. Rode traceback() imediatamente após o erro:
f <- function(x) g(x)
g <- function(x) stop("boom")
f(1)
# Error in g(x) : boom
traceback()
# 2: g(x)
# 1: f(1)
Ele imprime a pilha de chamadas no momento da falha - sua chamada em uma ponta, a chamada que falhou na outra. Precisa ser a próxima coisa que você executa; a pilha é descartada assim que outro erro ocorre.
Para uma visão ao vivo, browser() pausa a execução onde quer que você o plante e te deixa em um prompt interativo dentro da função - inspecione variáveis, avance com n, continue com c, saia com Q. debug(f) faz o mesmo sem editar código: marca f para que sua próxima chamada abra no browser (desfaça com undebug(f)).
E aí tem a técnica que ninguém coloca em slides de conferência mas todo mundo usa: imprimir. Espalhe print() ou cat() em pontos de checagem, execute e veja onde a realidade para de bater com sua expectativa. É legítimo, é rápido e, em scripts, muitas vezes é a ferramenta mais prática. Seu melhor amigo é o str(), que responde à pergunta por trás de talvez metade de todos os erros do R - "o que esse objeto é de verdade?":
Uma leitura compacta: é uma lista, dois elementos, um vetor de inteiros e um data frame com estas colunas e tipos. Quando um $ falha ou a matemática se comporta mal, dê um str() no objeto antes de teorizar - a resposta normalmente está bem ali ("...ah, é uma lista de comprimento 1 contendo o meu data frame").
O Que Você Leva Daqui
- Leia a mensagem: a parte depois de
Error indiz onde, a parte depois dos dois pontos diz por quê. Corrija o primeiro erro, não o mais barulhento. object not found= erro de digitação, código ainda não executado ou uma variável que só existia dentro de uma função.could not find function= chamada alibrary()faltando, quase sempre.unexpected symbolsignifica gramática impossível de analisar - e o erro real muitas vezes é uma aspa ou parêntese não fechado antes do ponto sinalizado.- Os clássicos de tipo/índice -
non-numeric argument,subscript out of bounds,$em vetores atômicos,argument is of length zero- apontam cada um para uma suposição errada sobre o que um objeto é;str()confere a suposição em uma chamada. - Avisos não interrompem a execução, e é exatamente por isso que merecem atenção - o resultado pode estar silenciosamente errado.
tryCatch(error =, warning =, finally =)trata falhas esperadas sem morrer (sempre registreconditionMessage());traceback()logo após um erro mostra a cadeia de chamadas;browser()/debug()pausam dentro dela; depurar comprint()é trabalho honesto.
A seguir: muitos "erros" que nem são erros remontam a um valor de dois caracteres - o NA, e como valores ausentes fluem por tudo o que o R calcula.
Perguntas frequentes
O que significa "object 'x' not found" no R?
O R procurou uma variável chamada x e nenhum nome desses existe em qualquer ambiente que ele pesquisou. As causas, em ordem de probabilidade: um erro de digitação no nome (o R diferencia maiúsculas de minúsculas - Total não é total), a linha que cria x ainda não foi executada nesta sessão, ou x foi criado dentro de uma função e você está tentando usá-lo fora.
O que significa "could not find function" no R?
A função existe em um pacote que você não carregou nesta sessão. Instalar um pacote é uma vez por máquina; library() é uma vez por sessão, e esquecer a chamada a library() é a causa usual. Se o próprio library() falhar, o pacote não está instalado. Um erro de digitação no nome da função produz o mesmo erro.
Como tratar erros no R com tryCatch?
Envolva a expressão arriscada: tryCatch(expr, error = function(e) alternativa, warning = function(w) alternativa, finally = limpeza). Se expr falhar, o handler correspondente roda em vez de o script morrer, e o que o handler retornar vira o resultado. conditionMessage(e) dentro de um handler te dá a mensagem original para registro.
O que traceback() faz no R?
Executado imediatamente após um erro, traceback() imprime a cadeia de chamadas de função que estava ativa quando o erro disparou - sua chamada em uma ponta, a chamada que falhou na outra. Ele não conserta nada; diz onde olhar, que é a maior parte da batalha quando o erro veio do fundo de funções aninhadas.