Describe the bug
A READ request against a draft-enabled entity carrying the auto-injected @UI.Recommendations annotation crashes with a 500 when the incoming query has no explicit SELECT.columns:
TypeError: Cannot read properties of undefined (reading 'findIndex')
at GlobalHandler.<anonymous> (.../@cap-js/ai/lib/handlers/recommendations.js:48:59)
at next (.../@sap/cds/lib/srv/srv-dispatch.js:57:36)
at GlobalHandler.handle (.../@sap/cds/lib/srv/srv-dispatch.js:60:6)
Root cause: in lib/handlers/recommendations.js, the READ handler guards (lines 24–31) check req.query.elements[...] before proceeding, but line 48 then dereferences req.query.SELECT.columns.findIndex(...) without checking that req.query.SELECT.columns exists:
const recommendationsIdx = req.query.SELECT.columns.findIndex(
(col) => col.ref && col.ref[0] === req.target?.['@UI.Recommendations']['=']
);
When the request reaches this handler on a draft entity that has the recommendations struct selected, but the underlying SELECT has no columns array populated (a normal shape for certain OData V4 draft READs), .columns is undefined and .findIndex throws. The guard on line 27 validates req.query.elements, not req.query.SELECT.columns, so the request passes the guards and crashes.
Environment:
| Package |
Version |
@sap/cds |
9.7.1 |
@cap-js/ai |
1.0.1 (latest) |
| node |
24.18.0 |
To Reproduce
Steps to reproduce the behavior:
- Install
@cap-js/ai in a CAP project.
- Expose a
@odata.draft.enabled entity with a value-help field (@Commor @cds.odata.valueliston the association target) — the pluginauto-injects@UI.Recommendations`.
- Issue an OData V4 READ whose query carries the recommendations struct b
- The request returns a 500 with
TypeError: Cannot read properties of undefined (reading 'findIndex') at recommendations.js:48.
Minimal isolated reproduction (invokes only the recommendations READ handlre):
import cds from '@sap/cds';
import registerHandlersForRecommendations from '@cap-js/ai/lib/handlers/recommendations.js';
const RECO_TARGET = 'MyService.MyEntity.recommendations';
cds.model = { definitions: { [RECO_TARGET]: { elements: { technicalRecommendationsIdentifier: {}, field1: {} } } } };
cds.context = { model: cds.model };
let readHandler;
registerHandlersForRecommendations({ prepend: (fn) => fn(), on: (e, fn) =>ler = fn; } });
const STRUCT = 'SAP_Recommendations';
const req = {
target: {
isDraft: true, name: 'MyService.MyEntity',
'@UI.Recommendations': { '=': STRUCT },
actives: {
'@UI.Recommendations': { '=': STRUCT },
elements: { ID: { type: 'cds.UUID' }, [STRUCT]: { target: RECO_TARGET } },
},
elements: { ID: { type: 'cds.UUID' } },
keys: { ID: {} },
},
query: {
elements: { [STRUCT]: {} }, // struct selected -> passes
SELECT: { from: { ref: ['MyEntity'] } }, // no `columns` -> line 48 dereferences undefined
},
_: { event: 'READ' },
};
await readHandler(req, async () => [{ ID: '1' }]);
// -> TypeError: Cannot read properties of undefined (reading 'findIndex') at recommendations.js:48:59
Please contact me internally, so I can share the project to install the library and simulate the reported issue.
Expected behavior
The handler should guard against a missing req.query.SELECT.columns (e.g skip the splice) and not throw a 500. A READ that does not carry anexplicit column list should degrade gracefully rather than crash.
[ ] is it a regression issue?
No — @cap-js/ai has only ever had version 1.0.1 published, so there is no earlier version where this worked.
Customer Info
Company: SAP (I840577)
Describe the bug
A READ request against a draft-enabled entity carrying the auto-injected
@UI.Recommendationsannotation crashes with a 500 when the incoming query has no explicitSELECT.columns:Root cause: in
lib/handlers/recommendations.js, the READ handler guards (lines 24–31) checkreq.query.elements[...]before proceeding, but line 48 then dereferencesreq.query.SELECT.columns.findIndex(...)without checking thatreq.query.SELECT.columnsexists:When the request reaches this handler on a draft entity that has the recommendations struct selected, but the underlying
SELECThas nocolumnsarray populated (a normal shape for certain OData V4 draft READs),.columnsisundefinedand.findIndexthrows. The guard on line 27 validatesreq.query.elements, notreq.query.SELECT.columns, so the request passes the guards and crashes.Environment:
@sap/cds@cap-js/aiTo Reproduce
Steps to reproduce the behavior:
@cap-js/aiin a CAP project.@odata.draft.enabledentity with a value-help field (@Commor@cds.odata.valueliston the association target) — the pluginauto-injects@UI.Recommendations`.TypeError: Cannot read properties of undefined (reading 'findIndex')atrecommendations.js:48.Minimal isolated reproduction (invokes only the recommendations READ handlre):
Please contact me internally, so I can share the project to install the library and simulate the reported issue.
Expected behavior
The handler should guard against a missing
req.query.SELECT.columns(e.g skip the splice) and not throw a 500. A READ that does not carry anexplicit column list should degrade gracefully rather than crash.[ ] is it a regression issue?
No —
@cap-js/aihas only ever had version 1.0.1 published, so there is no earlier version where this worked.Customer Info
Company: SAP (I840577)