Skip to content

Completing a series instrument logs a TypeError "Cannot read properties of undefined (reading 'kind')" #1813

Open

Description

@gdevenyi

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

  1. After the last item is submitted, the submit handler increments the item index to items.length:
  2. The scalar bundle is then undefined, and the renderer passes an empty string to the hook:
    const scalarBundle = target.items[currentItemIndex]?.bundle;
    const scalarId = target.items[currentItemIndex]?.id;
    const rootState = useInterpretedInstrument<UnilingualSeriesInstrument>(target.bundle);
    const scalarState = useInterpretedInstrument<AnyUnilingualScalarInstrument>(scalarBundle ?? '');
  3. The hook interprets every bundle, including '', and logs every rejection with console.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]);
  4. evaluateInstrument('') runs new Function('return ')(), which returns undefined:
    return await new Function(`return ${bundle}`)();
  5. Without validate, the try block does not throw. The instrument.kind access is outside the try, so it throws a raw TypeError:
    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

  1. Open a series instrument (for example, in the playground or as a remote assignment).
  2. Complete all items.
  3. 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 accept null and skip the effect). Or, in SeriesInstrumentRenderer, do not request a scalar instrument when currentItemIndex >= target.items.length.
  • Also, in InstrumentInterpreter.interpret, reject a non-object result inside the try block, so that a bad bundle gives the normal "Failed to evaluate instrument bundle" error and not a raw TypeError.

cc @joshunrau (last change to these files)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions