Skip to content

Commit 88b838c

Browse files
jcschaffclaude
andcommitted
Fix NPE in StochMathMapping.getProbabilityRate for symbol-less rate expressions
`Expression.getSymbols()` is documented to return null when the expression has no free symbols (see Expression.java:545). The general-kinetics path in StochMathMapping was iterating over the result with an unguarded for-each, producing an NPE whose corpus signature is: Cannot read the array length because "<local7>" is null at cbit.vcell.mapping.StochMathMapping.getProbabilityRate (StochMathMapping.java:145) This trips when a non-mass-action rate expression flattens to a constant or otherwise contains no free symbols (e.g. a Michaelis-Menten rate where all parameters and species have already been resolved upstream). The fix mirrors the established null-guard pattern already used in AbstractStochMathMapping.getSubstitutedExpr (line 155). The general-kinetics fallback in StochasticTransformer is the intended path for non-mass-action kinetics — it takes the authoritative reaction rate as a net flux and uses max(rate, 0) as the irreversible forward rate, which is exactly the right shape for stochastic simulation. The NPE was preventing that path from completing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c5f4f2c commit 88b838c

1 file changed

Lines changed: 5 additions & 1 deletion

File tree

vcell-core/src/main/java/cbit/vcell/mapping/StochMathMapping.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,11 @@ private Expression getProbabilityRate(ReactionStep reactionStep, GeneralKinetics
142142

143143
// collect symbolTableEntries for speciesContexts within netRateExpr and replace with concentration parameter
144144
netRateExpr = new Expression(netRateExpr);
145-
for (String symbol : netRateExpr.getSymbols()) {
145+
// Expression.getSymbols() returns null when the expression has no free symbols
146+
// (e.g. a constant rate, or a rate that only references already-resolved values).
147+
String[] symbols = netRateExpr.getSymbols();
148+
for (int i = 0; symbols != null && i < symbols.length; i++) {
149+
String symbol = symbols[i];
146150
SymbolTableEntry symbolTableEntry = netRateExpr.getSymbolBinding(symbol);
147151
if (symbolTableEntry instanceof Kinetics.KineticsProxyParameter proxyParameter
148152
&& proxyParameter.getTarget() instanceof SpeciesContext sc) {

0 commit comments

Comments
 (0)