Skip to content

Generic CREATE/UPDATE & DELETE/CANCEL handlers crash on string-form query target — "Cannot read properties of undefined (reading 'length') #462

Description

@agustino-lim

Describe the bug

The generic handlers registered by handle_attachments for every application service crash on ordinary, non-attachment writes when the query's target is expressed as a string (entity name) rather than a { ref: [...] } object.

Two conditions in lib/plugin.js (v3.12.2 and current main) dereference .ref unconditionally:

// before(["CREATE","UPDATE"])  — ~line 492
if (req.query?.INSERT?.into.ref.length > 1) {

// before(["DELETE","CANCEL"])  — ~line 574
if (req.query?.DELETE?.from?.ref.length > 1) {

When into / from is a string (e.g. from INSERT.into('My.Entity') / DELETE.from('My.Entity') — a documented, valid form per capire › cds.ql), .ref is undefined, so .ref.length throws:

TypeError: Cannot read properties of undefined (reading 'length')

Two things make this worse:

  • These two blocks have no isAttachmentsEntity / hasAttachmentsComposition guard (unlike every other handler in the impl), so they run for all CREATE/UPDATE/DELETE across the app — including entities that have nothing to do with attachments.
  • The code is internally inconsistent: the DELETE line already guards from?. but not ref?.; the INSERT line guards neither into?. nor ref?..

This is distinct from #429 ("Remove wrong req.query assumption"), which fixed the outer req.query being absent. That fix shipped in 3.12.0, but the inner into.ref / from.ref deref remains in 3.12.2 and on main.

Real-world impact: this is deploy-blocking for us. A startup data-replication step writes federated data to local entities using the string-form target (UPSERT(rows).into('<entity name>')); with @cap-js/attachments enabled, the unguarded handler trips on these plain inserts and the boot/deploy fails. We currently work around it with a patch-package patch adding the optional chaining.

To Reproduce

Steps to reproduce the behavior:

  1. A CAP (Node.js) project with @cap-js/attachments@3.12.2 enabled (cds.requires.attachments), containing at least one entity with Composition of many Attachments (so the plugin activates) plus any plain entity:

    using { Attachments } from '@cap-js/attachments';
    entity Incidents { key ID: UUID; attachments: Composition of many Attachments; }
    entity Books     { key ID: Integer; title: String; }
    
    service MyService {
      entity Incidents as projection on Incidents;
      entity Books     as projection on Books;
    }
  2. Issue a write whose target is the string form, dispatched through the service:

    const srv = await cds.connect.to('MyService');
    await srv.run( INSERT.into('MyService.Books').entries({ ID: 1, title: 'x' }) );
    // and/or
    await srv.run( DELETE.from('MyService.Books').where({ ID: 1 }) );
  3. Observe the crash thrown from node_modules/@cap-js/attachments/lib/plugin.js at the INSERT?.into.ref.length line (~492) and, for the delete, the DELETE?.from?.ref.length line (~574):

    TypeError: Cannot read properties of undefined (reading 'length')
    

Expected behavior

A string-form (ref-less) target is valid CQN and should be tolerated. The handler should treat "no .ref / not a multi-segment path" as "not a child-entity write" and simply skip its composition check, rather than throwing:

if (req.query?.INSERT?.into?.ref?.length > 1) { … }
if (req.query?.DELETE?.from?.ref?.length > 1) { … }

[ ] is it a regression issue? — No (present since the composition-limit handlers were introduced; #429 fixed a related but different outer-req.query crash).

Environment

  • @cap-js/attachments: 3.12.2
  • @sap/cds: 9.x
  • Node.js: 22

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions