mobx-state-tree icon indicating copy to clipboard operation
mobx-state-tree copied to clipboard

improve error message on snapshot-model discrepancies

Open jayarjo opened this issue 7 years ago • 8 comments
trafficstars

When checking a snapshot for compliance to the root model (in case of failure) typecheck dumps out the whole snapshot and the whole type tree, making it nearly impossible to visually locate discrepancy. Could it output only the point of discrepancy between snapshot and model instead? Or at least output it at a separate line?

jayarjo avatar Mar 26 '18 17:03 jayarjo

I have the same pain point. My local workaround, when big arrays are involved, is to catch the error from create and then run create call separately for each array item separately. that way it will throw again, but with granular error

Bnaya avatar Mar 30 '18 21:03 Bnaya

Hey @jayarjo, I think what you ask is happening already (or maybe you want more detailed information) In the second error in the console log, the first line of the call stack is the thing, I suppose, you're looking for.

screen shot 2018-03-31 at 12 32 27

maxgallo avatar Mar 31 '18 11:03 maxgallo

It is not a problem when snapshot is small. You should try a nested one, with hundreds of items in arrays somewhere down the tree.

jayarjo avatar Apr 01 '18 15:04 jayarjo

I don't have a direct experience with hundreds of object, I daily have to deal with dozens of objects max. In my experience usually the first few lines of the stack trace, after the big dump of the whole thing, are really useful.

maxgallo avatar Apr 04 '18 22:04 maxgallo

Problem is clear, PRs improving this are welcome

mweststrate avatar Jul 12 '18 11:07 mweststrate

Problem is clear, PRs improving this are welcome

So the improvement would be to... display the model where the offense is happening versus the entire model that is type-checked? Or how about don't display any data blob and just show the offending properties? Throwing my hat in the ring...

Given the model:

import { types as t } from 'mobx-state-tree'

export default t.model('statement', {
  id: t.string,
  label: t.string,
  transactions: t.array(
    t.model('transaction', {
      id: t.string,
      amount: t.maybeNull(t.number),
      completed_on: t.model('dateSignature', {
        // YYYY-MM-DD
        date: t.refinement('serverDateFormat', t.string, value => {
          return Boolean(value.match(/^[1-9]\d{3}-[01]\d-[0123]\d/))
        })
      })
    })
  )
})

And the server data from a network request:

import statementModel from './models/statement'

const statement = statementModel.create({
  id: 'daf672da-9195-4804-b177-9d09c45d3b8e',
  label: ['October Week 1'],
  transactions: [
    {
      id: 'e10945f5-c426-49d2-b40e-18b7d5122085',
      amount: 24.47
    },
    {
      id: 'c6f12693-41bb-4fdd-b450-667c52315d68',
      amount: false
    },
    {
      id: false,
      amount: 51.68,
      completed_on: {
        date: '01/15/2020'
      }
    }
  ]
})

Output:

[mobx-state-tree] Error converting data to model 'statement':

- Expected
+ Received

<root>.label
  - string
  + [
       'October Week 1'
     ]
<root>.transactions[1].amount
  - (number | null)
  + false
<root>.transactions[2].id
  - string
  + false
<root>.transactions[2].completed_on.date
  - 'serverDateFormat' refinement
  + '01/15/2020'

And for easier machine parsing:

Not sure how kosher it is to extend the Error object with custom properties, but the offending paths and values can be passed as separate properties on the Error object too that you can collect for error logging and analytics.

console.log(error.typeCheckPaths)
/*
[
  {
    path: '<root>.label',
    expected: 'string',
    value: `[
       'October Week 1'
     ]`
  },
  {
    path: '<root>.transactions[1].amount',
    expected: '(number | null )',
    value: 'false'
  }
  ....
]
*/

sendAnalytics(error.name, { paths: error.typeCheckPaths })

jaythomas avatar Feb 18 '20 04:02 jaythomas

Extending Errors objects is perfectly fine. Feel free to PoC something in a PR

Op di 18 feb. 2020 04:14 schreef Jay Thomas [email protected]:

Problem is clear, PRs improving this are welcome

So the improvement would be to... display the model where the offense is happening versus the entire model that is type-checked? Or how about don't display any data blob and just show the offending properties? Throwing my hat in the ring...

Given the model:

import { types as t } from 'mobx-state-tree' export default t.model('statement', { id: t.string, label: t.string, transactions: t.array( t.model('transaction', { id: t.string, amount: t.maybeNull(t.number), completed_on: t.model('dateSignature', { // YYYY-MM-DD date: t.refinement('serverDateFormat', t.string, value => { return Boolean(value.match(/^[1-9]\d{3}-[01]\d-[0123]\d/)) }) }) }) ) })

And the server data from a network request:

import statementModel from './models/statement' const statement = statementModel.create({ id: 'daf672da-9195-4804-b177-9d09c45d3b8e', label: ['October Week 1'], transactions: [ { id: 'e10945f5-c426-49d2-b40e-18b7d5122085', amount: 24.47 }, { id: 'c6f12693-41bb-4fdd-b450-667c52315d68', amount: false }, { id: false, amount: 51.68, completed_on: { date: '01/15/2020' } } ] })

Output:

[mobx-state-tree] Error converting data to model 'statement':

  • Expected
  • Received

.label

  • string
  • [ 'October Week 1' ] .transactions[1].amount
  • (number | null)
  • false .transactions[2].id
  • string
  • false .transactions[2].completed_on.date
  • 'serverDateFormat' refinement
  • '01/15/2020'

And for easier machine parsing:

Not sure how kosher it is to extend the Error object with custom properties, but the offending paths and values can be passed as separate properties on the Error object too that you can collect for error logging and analytics.

console.log(error.typeCheckPaths)/[ { path: '.label', expected: 'string', value: [ 'October Week 1' ] }, { path: '.transactions[1].amount', expected: '(number | null )', value: 'false' } ....]/ sendAnalytics(error.name, { paths: error.typeCheckPaths })

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/mobxjs/mobx-state-tree/issues/734?email_source=notifications&email_token=AAN4NBB2EPK5SKY4T7OBUCTRDNOD3A5CNFSM4EXOG4V2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEMAQOGY#issuecomment-587269915, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAN4NBF3RMT57U5PCOI5YZLRDNOD3ANCNFSM4EXOG4VQ .

mweststrate avatar Feb 18 '20 09:02 mweststrate

I had to abandon my work on this project but I just wanted to point out a discovery I made; Large objects which extend the message size to 1MB will be forcibly truncated in Firefox, and Chrome does the same around I think it was 3~4MB(?).

This means with the current formatting the relevant "at path" information in the message may be truncated out the message.

jaythomas avatar Apr 03 '20 17:04 jaythomas