Menu

Erros Comuns do R e Como Depurá-los

Um decodificador para as mensagens de erro clássicas do R - object not found, could not find function, non-numeric argument e companhia - mais tryCatch, traceback() e a honesta depuração com print.

Esta página tem editores executáveis - edite, execute e veja a saída na hora.

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, total e TOTAL sã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 in diz 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 a library() faltando, quase sempre.
  • unexpected symbol significa 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 registre conditionMessage()); traceback() logo após um erro mostra a cadeia de chamadas; browser()/debug() pausam dentro dela; depurar com print() é 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.

Coddy programming languages illustration

Aprenda a programar com o Coddy

COMEÇAR