Repository navigation
Completing a series instrument logs a TypeError "Cannot read properties of undefined (reading 'kind')" #1813
Description
Problem
When a subject completes the last item of a series instrument, the browser console shows an error:
TypeError: Cannot read properties of undefined (reading 'kind')
The UI is correct (the "Thank You" screen shows), but each completed series logs this error. The error is noise and can hide real errors.
Cause
- After the last item is submitted, the submit handler increments the item index to
items.length:
OpenDataCapture/packages/react-core/src/components/InstrumentRenderer/SeriesInstrumentRenderer.tsx
Line 115 in 432dec8
setCurrentItemIndex(currentItemIndex + 1); - The scalar bundle is then
undefined, and the renderer passes an empty string to the hook:
OpenDataCapture/packages/react-core/src/components/InstrumentRenderer/SeriesInstrumentRenderer.tsx
Lines 65 to 69 in 432dec8
const scalarBundle = target.items[currentItemIndex]?.bundle; const scalarId = target.items[currentItemIndex]?.id; const rootState = useInterpretedInstrument<UnilingualSeriesInstrument>(target.bundle); const scalarState = useInterpretedInstrument<AnyUnilingualScalarInstrument>(scalarBundle ?? ''); - The hook interprets every bundle, including
'', and logs every rejection withconsole.error:
useEffect(() => { // A bundle that resolves after the hook has moved on to another one would otherwise be reported // as the outcome of that other bundle, or leave this stuck reporting LOADING for it forever. let isCurrent = true; interpreter .interpret(bundle, options) .then((instrument) => { if (isCurrent) { setInterpretation({ bundle, instrument, status: 'DONE' }); } }) .catch((error: unknown) => { console.error(error); if (isCurrent) { setInterpretation({ bundle, error: error instanceof Error ? error : new Error('Unexpected Non-Error Thrown', { cause: error }), status: 'ERROR' }); } }); return () => { isCurrent = false; }; }, [bundle]); evaluateInstrument('')runsnew Function('return ')(), which returnsundefined:
return await new Function(`return ${bundle}`)(); - Without
validate, thetryblock does not throw. Theinstrument.kindaccess is outside thetry, so it throws a rawTypeError:
OpenDataCapture/packages/instrument-interpreter/src/index.ts
Lines 18 to 30 in 432dec8
try { value = await evaluateInstrument(bundle); instrument = options?.validate ? await $AnyInstrument.parseAsync(value) : (value as AnyInstrument); } catch (error) { if (value) { console.error({ message: 'Validation Error', value }); } throw new Error(`Failed to evaluate instrument bundle`, { cause: error }); } if (instrument.kind !== 'INTERACTIVE') {
A series that ends through terminate does not have this problem, because the handler returns before it increments the index.
Steps to reproduce
- Open a series instrument (for example, in the playground or as a remote assignment).
- Complete all items.
- Open the browser console.
Expected: No error.
Actual: One TypeError: Cannot read properties of undefined (reading 'kind') is logged.
Suggested fix
- In
useInterpretedInstrument, do not interpret an empty bundle (or let the hook acceptnulland skip the effect). Or, inSeriesInstrumentRenderer, do not request a scalar instrument whencurrentItemIndex >= target.items.length. - Also, in
InstrumentInterpreter.interpret, reject a non-object result inside thetryblock, so that a bad bundle gives the normal "Failed to evaluate instrument bundle" error and not a rawTypeError.
cc @joshunrau (last change to these files)
Activity