Sentry-javascript: Exceção sem erro capturada com as chaves: erro, cabeçalhos, mensagem, nome, ok

Criado em 28 out. 2019  ·  48Comentários  ·  Fonte: getsentry/sentry-javascript

Pacote + Versão

  • [x] @sentry/browser
  • [] @sentry/node
  • [] raven-js
  • [] raven-node _ (raven para o nó) _
  • [ ] de outros:
  • [x] @angular/core

Versão:

5.7.1 (@sentry/browser)
8.2.11 (@angular/core)

Descrição

Eu tenho a configuração inicial para o aplicativo Angular com ErrorInterceptor global
aqui como eu envio

    const eventId = Sentry.captureException(error.originalError || error);
    Sentry.showReportDialog({ eventId });

e recebo este (exceção sem erro capturada com as chaves: erro, cabeçalhos, mensagem, nome, ok) erro repetidamente e não consigo entender o que está errado na descrição e como reproduzi-lo.

Needs Reproduction

Comentários muito úteis

No momento, estamos usando o seguinte para ignorá-lo.

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

Todos 48 comentários

Isso significa que o objeto fornecido não é uma instância de Error que contém o rastreamento de pilha no aplicativo Angular.

Você deve (como a mensagem indica) usar Sentry.captureException(error.error) ou Sentry.captureException(error.message) dependendo de suas necessidades.

@kamilogorek oh ok) tnx

@kamilogorek ainda está recebendo esse erro, mesmo com isso

    const exception = error.error || error.message || error.originalError || error;
    const eventId = Sentry.captureException(exception);

+1, ainda estou recebendo esse erro, não importa como eu coloquei.

sentry.error-handler.ts

export class SentryErrorHandler extends GeneralErrorHandler {
  ...
  handleError(error) {
    ...
    const exception = error.originalError || error.error || error
    Sentry.captureException(exception)
  }
}

package.json

{
  ...
  "@angular/core": "^8.2.11",
  "@sentry/browser": "^5.7.1",
  ...
}

Eu decidi fazer isso

Sentry.init({
            dsn: environment.sentryUrl,
            beforeSend(event, hint) {
                /* tslint:disable:no-string-literal only-arrow-functions */
                const isNonErrorException =
                    event.exception.values[0].value.startsWith('Non-Error exception captured') ||
                    hint.originalException['message'].startsWith('Non-Error exception captured');
                /* tslint:enable:no-string-literal only-arrow-functions */

                if (isNonErrorException) {
                    // We want to ignore those kind of errors
                    return null;
                }
                return event;
            }
        });

Obrigado pela solução alternativa @gchronos! Espero que haja uma solução potencial em breve.

Estou apenas entrando na conversa para dizer que também estou recebendo esses erros. Estou usando o Angular 8 e depois de ler algumas questões sobre isso, percebo que pode ser o caso de eu não estar lidando com o erro adequadamente em meu componente de tratamento de erros. Eu tentei as soluções alternativas sugeridas por outros que definem a exceção antes de ser passada para captureException, mas isso não reduziu os erros. Seria ótimo se alguém pudesse fornecer mais informações sobre isso ou terei que usar a solução do GChronos (obrigado!).

+1

+1

Alguém pode fornecer repro que eu possa usar para depurar isso? Tentei usar o aplicativo angular-cli básico e não consigo reproduzir esse comportamento. Obrigado!

@kamilogorek Eu acredito que você pode

Posso entrar com mais algumas informações, este é o nosso ErrorHandler:

@Injectable()
export class SentryErrorHandler implements ErrorHandler {
  constructor() { }
  handleError(error) {
    Sentry.captureException(error.originalError || error.error || error);
  }
}

Em nosso rastreamento de Sentinelas, sempre obtemos eventos duplicados para estes:

  • Exceção de não erro
  • captureException Exceção sem erro capturada com chaves: ...

(Outros eventos são relatados como um item da lista)

Coletamos algumas centenas desses eventos "Non.Error" e, curiosamente, todos eles têm o seguinte em comum:

  • browser.name: Samsung Internet 100%
  • navegador: Samsung Internet 9,4 100%

E os erros são principalmente os seguintes:

{
  error: [Object], 
  headers: [Object], 
  message: Http failure during parsing for https://foo.bar/baz, 
  name: HttpErrorResponse, 
  ok: False, 
  status: 200, 
  statusText: OK, 
  url: https://foo.bar/baz
}

Ok, tornei o SentryErrorHandler injetável e implementa ErrorHandler em vez de estende e não há mais problemas como esse para mim.
Então eu mudei de

export class SentryErrorHandler extends ErrorHandler {

 constructor() {
     super();
 }

 handleError(err: any): void {
     if (environment.production === true || environment.preprod === true) {
         Sentry.captureMessage(err.originalError || err);
     }
     throw err;
 }
}

para

@Injectable()
export class SentryErrorHandler implements ErrorHandler {

 constructor() { }

 handleError(err: any): void {
     if (environment.production === true || environment.preprod === true) {
         Sentry.captureException(err.originalError || err);
     }
     throw err;
 }
}

Tive a primeira configuração por 2 anos sem problemas, mas desde a atualização para o Angular 8, tenho várias exceções de sentinela.

@jonathan-payiq, você conseguiu descobrir o que causa isso? Ou você simplesmente ignora todas as exceções sem erro agora?

No momento, estamos ignorando-os.
Descobrimos a partir da localização atual que isso acontece quando o webview / navegador está em segundo plano (não visível), portanto, a solução para nós é evitar que a busca aconteça enquanto a página não estiver visível. Aparentemente, os navegadores Samsung lidam mal com a atualização da rede quando em segundo plano.

@ jonathan-payiq exatamente como você os está ignorando? Desde já, obrigado.

No momento, estamos usando o seguinte para ignorá-lo.

Sentry.init({
  ignoreErrors: [
    'Non-Error exception captured'
  ]
});

@kamilogorek você conseguiu reproduzir o problema?

Fechando o problema, pois parece que o problema original foi parcialmente resolvido ou há uma solução funcionando. Eu preferiria que alguém criasse um novo problema com uma nova descrição, se ainda for um problema.
Por favor, não hesite em me enviar um ping se ainda for relevante, e terei o prazer de reabrir e trabalhar nisso.
Saúde!

Não foi resolvido. Eu apenas tentei integrar o Sentry com o Angular 8 e encontrei esse problema.

Eu não entendo como o Sentry pode reivindicar uma configuração fora da caixa, é completamente falso.

Eu não entendo como o Sentry pode reivindicar uma configuração fora da caixa, é completamente falso.

A @Rush fornece um caso reproduzível, onde você explica e mostra o que está errado, e então podemos verificar sua reclamação.

@kamilogorek Verdade seja dita, não

Exatamente e, além disso, estou pagando para que o Sentinela faça o trabalho por mim. Não é um projeto de código aberto onde espero sujar as mãos.

Gosto do Sentry mas posso procurar alternativas ...

Usei um aplicativo https://github.com/gothinkster/angular-realworld-example-app como exemplo, apenas para que todos possam fazer a mesma reprodução.

Barebone clonou o aplicativo, seguiu os documentos Angular do Sentry e carregou os mapas de origem. Aqui estão os resultados.


Exemplo 1: lógica quebrada

O que o Angular oferece em um gerenciador de erros + qual evento capturamos:

Screenshot 2020-04-16 at 12 01 13

Como fica na IU:

Screenshot 2020-04-16 at 12 07 02

Nota: Tudo está no lugar, você pode facilmente apontar para a linha correta de código que foi quebrada, a mensagem de erro e o tipo de erro estão corretos, porque o Angular fornece um objeto Error inteiro para trabalhar.


Exemplo 2: chamada de serviço interrompida

O que o Angular oferece em um gerenciador de erros + qual evento capturamos:

Screenshot 2020-04-16 at 12 00 49

Como fica na IU:

Screenshot 2020-04-16 at 12 07 12
Screenshot 2020-04-16 at 12 08 03

Observação: não há como saber que tipo de erro foi gerado, porque o Angular não fornece essa informação. No entanto, você pode dar uma olhada nos dados serializados para saber que houve o erro "404 não encontrado", que _mais provavelmente_ veio de uma chamada XHR inválida. Em seguida, você pode investigar o fluxo de breadcrumbs para ver se _de fato_ houve uma chamada XHR para o url fornecido (que neste caso continha um erro de digitação), precedida por um clique em um elemento DOM exato, que o acionou. Com essa informação, deve ser suficiente em 99% dos casos para consertar o problema.


Só podemos trabalhar com o que nos foi fornecido pelo framework. Caso contrário, teríamos que corrigir o próprio framework.

Só podemos trabalhar com o que nos foi fornecido pelo framework. Caso contrário, teríamos que corrigir o próprio framework.

É esta a sua maneira de dizer "não é nosso problema"? Antes de mudar para o sentry (de alguns concorrentes), esses erros XHR foram capturados muito bem e eles usaram o mesmo método de instalação com um manipulador de erros angular.

@kamilogorek como fornecedor, você também pode abrir um tíquete com o framework. Tenho certeza que chamaria alguma atenção.

Antes de mudar para o sentry (de alguns concorrentes), esses erros XHR foram capturados muito bem e eles usaram o mesmo método de instalação com um manipulador de erros angular.

@szechyjs, então seria ótimo se você pudesse compartilhar a solução em vez disso, já que é um SDK de código aberto e podemos iterar nas melhorias se soubermos o que queremos.

... você também pode abrir um tíquete com o framework. Tenho certeza que chamaria alguma atenção.

Acabei de abrir um tíquete com suporte de sentinela e mencionei esse problema.

Um transeunte aqui. Para o meu caso, quero relatar rejeições tratadas no react nativo e acabei vendo o mesmo erro que o OP. Desde the object you provide is not an instance of Error , comecei a usar o abaixo.

export interface IError extends Error {
  code?: ErrorCode
  msg?: string
}

export const appError = (code: ErrorCode, msg: string = ''): IError => {
  const errmsg = `code: ${code}, msg: ${msg}`
  const err: IError = new Error(errmsg)
  err.code = code
  err.msg = msg
  err.name = 'appError'
  return err
}

Então eu ligo

export const logError = (err: Error) => {
  sentry.captureException(err)
}

e eu vejo

スクリーンショット 0032-05-24 1 58 38

Espero que isto ajude!

No meu caso, a seção Breadcrumbs do Sentry me ajudou muito a identificar a causa. Aconteceu principalmente quando havia cerca de 404 em algumas APIs externas.

A atualização do Docs e a mudança necessária do JS SDK estão chegando:

https://github.com/getsentry/sentry-docs/pull/1695/
https://github.com/getsentry/sentry-javascript/pull/2601

Deve ser lançado esta semana! :)

Correção fácil para isso (pois isso só acontece com erros interceptados de HTTP):

handleError(error: Error | HttpErrorResponse | any) {
      // ... 
      if (error.constructor.name === "HttpErrorResponse") {
                error.error.Message + " (" + error.message + ")";
                error = error.error;
      }
      // ...
      Sentry.captureMessage(err.originalError || err.error || error);

     throw err;
 }

Novos documentos e 5.16.0 acabaram de ser lançados - https://docs.sentry.io/platforms/javascript/angular/
Tentei torná-lo o mais explícito e detalhado possível, e é por isso que "pode ​​parecer" muito código.

@kamilogorek Estou tendo esse problema em um aplicativo Vue também. Existe uma correção aí?

Mesmo aqui. a exceção é lançada no manipulador de erros de integração vuejs sentry.
https://sentry.io/share/issue/eaf13a2455e04150aaaab595d0d7bafe/

@sblawrie que problema exatamente você tem? Mais alguns detalhes seriam úteis, por favor.
@cincauhangus parece que em algum lugar do seu código você está gerando um erro com a própria instância da promessa (observe abort, always, catch, done keys).

Algo como:

const promise = new Promise((resolve, reject) => (...));
// somehow somewhere in the code
function foo () {
  // ...
  throw promise
}

Portanto, o errorHandler do Vue está obtendo um objeto de promessa inteiro, onde espera ser uma instância Error .

@kamilogorek obrigado pelo esclarecimento. Fiz algumas alterações e monitorarei se ainda for um problema.

Usando Angular 8 e teve o mesmo problema de exceção sem erro. Modificou o código de exemplo 'extractError' da seguinte forma:

private static extractError(error: any) {
    // Try to unwrap zone.js error.
    // https://github.com/angular/angular/blob/master/packages/core/src/util/errors.ts
    if (error && error.ngOriginalError) {
      error = error.ngOriginalError;
    }
    // We can handle messages and Error objects directly.
    if (typeof error === 'string' || error instanceof Error) {
      return error;
    }
    // If it's http module error, extract as much information from it as we can.
    if (error instanceof HttpErrorResponse) {
      // The `error` property of http exception can be either an `Error` object, which we can use directly...
      if (error.error instanceof Error) {
        return error.error;
      }
      // ... or an`ErrorEvent`, which can provide us with the message but no stack...
      if (error.error instanceof ErrorEvent) {
        return error.error.message;
      }
      // ...or the request body itself, which we can use as a message instead.
      if (typeof error.error === 'string') {
        return `Server returned code ${error.status} with body "${error.error}"`;
      }
      // If we don't have any detailed information, fallback to the request message itself.
      return error.message;
    }

    // ***** CUSTOM *****
    // The above code doesn't always work since 'instanceof' relies on the object being created with the 'new' keyword
    if (error.error && error.error.message) {
      return error.error.message;
    }
    if (error.message) {
      return error.message;
    }
    // ***** END CUSTOM *****

    // Skip if there's no error, and let user decide what to do with it.
    return null;
  }

Modifiquei meu Sentry.init beforeSend baseado em exemplo beforeSend 's @untilinvite acima. Essa mudança é para lidar com uma segunda mensagem de log de https://github.com/getsentry/sentry-javascript/issues/2169 também resolvida como um Não-erro.

 Sentry.init({
        dsn: AppConfig.envSettings.sentryDSN,
        maxBreadcrumbs: 50,
        environment: this.getEnvName(),
        integrations: [new Sentry.Integrations.Breadcrumbs({ console: false })],
        beforeSend(event, hint) {
          // Note: issue with double entries during http exceptions: https://github.com/getsentry/sentry-javascript/issues/2169
          // Note: issue with a second entry not being set correctly (as a non-error): https://github.com/getsentry/sentry-javascript/issues/2292#issuecomment-554932519
          const isNonErrorException = event.exception.values[0].value.startsWith('Non-Error exception captured');
          if (isNonErrorException) {
            if (!event.extra.__serialized__) {
              return null;
            }
            let realErrMsg = event.extra.__serialized__.error ? event.extra.__serialized__.error.message : null;
            realErrMsg = realErrMsg || event.extra.__serialized__.message;
            // this is a useless error message that masks the actual error.  Lets try to set it properly
            event.exception.values[0].value = realErrMsg;
            event.message = realErrMsg;
          }
          return event;
        }
      });

Fizemos as alterações que foram adicionadas aos documentos com a versão 5.16.0 e ainda estamos recebendo Non-Error exception captured with keys: error, headers, message, name, ok erros. Espero que o pacote @ sentry / angular corrija esses problemas.

Angular: v9.1
Sentinela: v5.20

@szechyjs você também leu a segunda parte sobre interceptores http? Geralmente, esse é o principal problema que faz com que o erro não seja detectado corretamente - https://docs.sentry.io/platforms/javascript/angular/

@szechyjs você também leu a segunda parte sobre interceptores http? Geralmente, esse é o principal problema que faz com que o erro não seja detectado corretamente - https://docs.sentry.io/platforms/javascript/angular/

Não estamos usando interceptores.

Olá, dediquei algum tempo a este problema e descobri que error.error.message em erros do tipo HttpErrorResponse não contém necessariamente qualquer informação. Se olharmos para o construtor, veremos que o Angular define a prop da mensagem no objeto raiz e não em ErrorEvent .

https://github.com/angular/angular/blob/cb3db0d31b91bea14c7f567fe7e7220b9592c11b/packages/common/http/src/response.ts#L345

Ao alterar esta linha https://github.com/getsentry/sentry-javascript/blob/8eb72865dcd62ff719441105c7eda28007a07e9d/packages/angular/src/errorhandler.ts#L112
para

if (error.error instanceof ErrorEvent && error.error.message)

o manipulador de erros procedeu a return error.message; e lançou o erro esperado.

Grande captura @jakkn , obrigado! Manipulador atualizado no PR https://github.com/getsentry/sentry-javascript/pull/2903

Estou tendo esse problema em um aplicativo Express que acabei de herdar. Não tenho ideia de como isso pode acontecer, mas parece que está acontecendo para a maioria dos erros que o aplicativo lança, e estou usando a configuração Express padrão dos documentos.

por exemplo, https://sentry.io/share/issue/bfd4f674c10b4b4a8b6a291dde8e2a66/

Eu encontrei o mesmo erro, embora fosse para o gerenciador de solicitação expressa e não angular. Basicamente, eu estava chamando next com um pojo em vez de um objeto Error. Eu faço algumas coisas divertidas em meu próprio manipulador de erros expresso para transformá-lo em algo de interesse, mas como o middleware de solicitação do sentryio vai primeiro, ele não obteve esse erro de empacotamento.

No final, criou uma função de utilidade que tornaria tudo o que fosse fornecido em algo mais razoável:

export const handleMaybeError = err => {
  if (err instanceof Error) return err
  const newErr = new Error(err.message || 'unexpected')
  for (const [key, value] of Object.entries(err)) {
    newErr[key] = value
  }
  return newErr
}

export const someController = (req, res, next) => {
  try {
    await handleResponse(req, res)
  } catch (err) {
    next(handleMaybeError(err))
  }
}

Isso confunde os rastreamentos de pilha, eu acho, mas realmente se fosse um pojo passado para isso, não havia rastreio de pilha de qualquer maneira.

Em nossa instância, antes que isso fosse corrigido, a grande maioria dos eventos relatados era para esse problema específico e, como é um nó de servidor da web de longa execução, migalhas de pão são quase inúteis - e todos os erros são agrupados neste tipo de evento.

exceção const = error.error || mensagem de erro || error.originalError || erro;

isso será avaliado como verdadeiro / falso

exceção const = error.error || mensagem de erro || error.originalError || erro;

isso será avaliado como verdadeiro / falso

Improvável, embora possível. Tudo se resume a qual "erro" você envia ao longo do fluxo. Mas, afinal, isso deve incluir algum tipo de informação útil.

Esta página foi útil?
0 / 5 - 0 avaliações