I've been just tinkering, and the beginning of my sheetworkers section now looks like this. It seems like it might all be working properly, now, but we're still testing it. const repeatingSum = (destinations, section, fields) => { if (!Array.isArray(destinations)) destinations = [destinations.replace(/\s/g, '').split(',')]; if (!Array.isArray(fields)) fields = [fields.replace(/\s/g, '').split(',')]; getSectionIDs(`repeating_${section}`, idArray => { const attrArray = idArray.reduce((m, id) => [...m, ...(fields.map(field => `repeating_${section}_${id}_${field}`))], []); getAttrs([...attrArray], v => { const getValue = (section, id, field) => v[`repeating_${section}_${id}_${field}`] === 'on' ? 1 : parseFloat(v[`repeating_${section}_${id}_${field}`]) || 0; const commonMultipliers = (fields.length <= destinations.length) ? [] : fields.splice(destinations.length, fields.length - destinations.length); const output = {}; destinations.forEach((destination, index) => { output[destination] = idArray.reduce((total, id) => total + getValue(section, id, fields[index]) * commonMultipliers.reduce((subtotal, mult) => subtotal * getValue(section, id, mult), 1), 0); }); setAttrs(output); }); }); }; const sections = ['specials', 'arts', 'spaths', 'ppaths', 'dlores', 'misc', 'rituals', 'gear']; const stats_core = ['Strength', 'Dexterity', 'Charisma', 'Intelligence', 'Manipulation', 'Wits', 'Stamina', 'Composure', 'Resolve']; const stats_all = stats_core.reduce((all, one) => [...all, one, `m_${one}`, `m_${one}_mod`], []); const stat_changes = stats_all.reduce((changes, stat) => `change:${stat} ${changes}`, '').slice(0,-1).toLowerCase(); stats_core.forEach(function (stat) { on(`change:${stat}_base change:${stat}_bonus`, function () { getAttrs([`${stat}_base`, `${stat}_bonus`], function (values) { const stat_base = parseInt(values[`${stat}_base`])||0; const stat_bonus = parseInt(values[`${stat}_bonus`])||0; const final_total = stat_base + stat_bonus; setAttrs({ [`${stat}`]: final_total }); }); }); on(`change:m_${stat}_base change:m_${stat}_bonus`, function () { getAttrs([`m_${stat}_base`, `m_${stat}_bonus`], function (values) { const stat_base = parseInt(values[`m_${stat}_base`])||0; const stat_bonus = parseInt(values[`m_${stat}_bonus`])||0; const final_total = stat_base + stat_bonus; const stat_mod = (Math.floor((final_total * (final_total - 1))/2) + 1) * Math.ceil(final_total/15); setAttrs({ [`m_${stat}`]: final_total, [`m_${stat}_mod`]: stat_mod }); }); }); }); sections.forEach(section => { const special_attribute_name_string = 'attribute_name'; on(`${stat_changes} change:repeating_${section}:${special_attribute_name_string}`, () => { getSectionIDs(`repeating_${section}`, id_array => { const fieldnames = id_array.reduce((all, id) => [...all, `repeating_${section}_${id}_${special_attribute_name_string}`], []); getAttrs([...fieldnames, ...stats_all], values => { const output = {}; id_array.forEach(id => { const special_attribute_name = values[`repeating_${section}_${id}_${special_attribute_name_string}`]; output[`repeating_${section}_${id}_attribute_${section}`] = +values[special_attribute_name] || 0; output[`repeating_${section}_${id}_mattribute_${section}`] = +values[`m_${special_attribute_name}`] || 0; output[`repeating_${section}_${id}_mattribute_mod_${section}`] = +values[`m_${special_attribute_name}_mod`] || 0; }); setAttrs(output); }); }); }); }); Edit to add: the error message in the API console has also stopped appearing.