Summary
GET /api/v0/biomodel/{id}/biomodel.bngl returns HTTP 500 with Index 0 out of bounds for length 0
for any BioModel that has zero applications. A model with no application is perfectly legal,
so this is a routine input reaching an unguarded array access and surfacing as a server error.
Reproduce
$ curl -s -o /dev/null -w '%{http_code}\n' \
'https://vcell.cam.uchc.edu/api/v0/biomodel/321238605/biomodel.bngl'
500
$ curl -s 'https://vcell.cam.uchc.edu/api/v0/biomodel/321238605/biomodel.bngl'
status = (Index 0 out of bounds for length 0),
request = (GET http://vcell.cam.uchc.edu/api/v0/biomodel/321238605/biomodel.bngl HTTP/1.1),
response = (HTTP/1.1 - Internal Server Error (500) - Index 0 out of bounds for length 0)
Deterministic, not load-related. BioModel 321238605 (kartik-bm-new, public) reports
"applications": [].
Cause
BiomodelBNGLServerResource.java:118:
BioModel bioModel = XmlHelper.XMLToBioModel(new XMLSource(biomodelVCML));
SimulationContext chosenSimContext = bioModel.getSimulationContext(0); // <-- throws when there are none
RbmNetworkGenerator.writeBngl(chosenSimContext, pw, false, true);
With no simulation contexts, getSimulationContext(0) throws
ArrayIndexOutOfBoundsException, which the catch-all at the end of the method converts to
Status.SERVER_ERROR_INTERNAL.
Scope
The correlation is exact across a sample of six public models:
| bmKey |
applications |
biomodel.bngl |
| 321238605 |
0 |
500 |
| 320046667 |
1 |
200 |
| 320029568 |
1 |
200 |
| 316581880 |
4 |
200 |
| 315396932 |
1 |
200 |
| 315272981 |
1 |
200 |
It is not a rare shape: in the single listing GET /api/v0/biomodel?category=educational&maxRows=1000,
63 of 1000 models have zero applications, so every one of those 500s on this endpoint.
Suggested fix
Guard the empty case and return a client error that says what is wrong, rather than a 500 — e.g.
404 or 400 with "BioModel has no application; a BNGL export requires one". Two further points
worth deciding while in there:
- Silently picking index 0 is itself questionable for a model with several applications
(316581880 has 4). The caller has no way to choose, and no way to know which was exported.
- The
catch (Exception e) at the bottom maps every unexpected failure to a 500 carrying the raw
exception message, which is how an ArrayIndexOutOfBoundsException ended up as user-facing API
output.
How this surfaced
Found in the vcell-ai-rke-dev namespace, where the AI backend's vcelldb_service proxies to this
endpoint and logged four consecutive failures:
ERROR | vcelldb_service | HTTP error fetching BNGL file for biomodel 321238605:
500 - status = (Index 0 out of bounds for length 0)
Summary
GET /api/v0/biomodel/{id}/biomodel.bnglreturns HTTP 500 withIndex 0 out of bounds for length 0for any BioModel that has zero applications. A model with no application is perfectly legal,
so this is a routine input reaching an unguarded array access and surfacing as a server error.
Reproduce
Deterministic, not load-related. BioModel
321238605(kartik-bm-new, public) reports"applications": [].Cause
BiomodelBNGLServerResource.java:118:With no simulation contexts,
getSimulationContext(0)throwsArrayIndexOutOfBoundsException, which the catch-all at the end of the method converts toStatus.SERVER_ERROR_INTERNAL.Scope
The correlation is exact across a sample of six public models:
biomodel.bnglIt is not a rare shape: in the single listing
GET /api/v0/biomodel?category=educational&maxRows=1000,63 of 1000 models have zero applications, so every one of those 500s on this endpoint.
Suggested fix
Guard the empty case and return a client error that says what is wrong, rather than a 500 — e.g.
404or400with "BioModel has no application; a BNGL export requires one". Two further pointsworth deciding while in there:
(
316581880has 4). The caller has no way to choose, and no way to know which was exported.catch (Exception e)at the bottom maps every unexpected failure to a 500 carrying the rawexception message, which is how an
ArrayIndexOutOfBoundsExceptionended up as user-facing APIoutput.
How this surfaced
Found in the
vcell-ai-rke-devnamespace, where the AI backend'svcelldb_serviceproxies to thisendpoint and logged four consecutive failures: