Skip to content

[Version: 1.0.1] Runtime 500 "Cannot read properties of undefined (reading 'findIndex')" on draft READ when req.query.SELECT.columns is undefined #38

Description

@lucasborin

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:

  1. Install @cap-js/ai in a CAP project.
  2. Expose a @odata.draft.enabled entity with a value-help field (@Commor @cds.odata.valueliston the association target) — the pluginauto-injects@UI.Recommendations`.
  3. Issue an OData V4 READ whose query carries the recommendations struct b
  4. 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions