Smart action error type

Feature(s) impacted

handle a smart action

Observed behavior

when I click on action “Ajouter une transaction” i got this log error :

warning: [400] POST /forest/_actions/contacts/2/ajouter-une-transaction/hooks/load - 11ms

===== An exception was raised =====
POST /forest/_actions/contacts/2/ajouter-une-transaction/hooks/load?{
 timezone: Africa/Algiers
}

Body {
 data: {
  attributes: {
   ids: [
    8699
   ],
   collection_name: contacts,
   parent_collection_name: null,
   parent_collection_id: null,
   parent_association_name: null,
   all_records: false,
   all_records_subset_query: {
    fields[contacts]: id,nom_complet,due_date,action_a_mener_enum,status_enum,red_flag,regularite,solde_anticipe,
    page[number]: 1,
    page[size]: 15,
    sort: due_date,
    search: stephane.vincent@hevea-asso.fr,
    searchExtended: 0,
    isSearchExtended: false,
    timezone: Africa/Algiers
   },
   all_records_ids_excluded: [
    23396
   ],
   smart_action_id: contacts-Ajouter@@@une@@@transaction,
   signed_approval_request: null
  },
  type: action-requests
 }
}

 The given value has a wrong type for "tutee:id": 8699.
 Expects "Number",null 

ValidationError: The given value has a wrong type for "tutee:id": 8699.
 Expects "Number",null
    at FieldValidator.validateValue (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/validation/field.js:53:19)
    at ConditionTreeValidator.validateValues (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/validation/condition-tree.js:83:29)
    at ConditionTreeValidator.throwIfValueNotAllowedWithColumnType (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/validation/condition-tree.js:75:18)
    at ConditionTreeValidator.validateLeaf (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/validation/condition-tree.js:41:32)
    at ConditionTreeValidator.validate (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/validation/condition-tree.js:18:36)
    at OperatorsEmulateCollectionDecorator.computeEquivalent (/usr/src/app/node_modules/@forestadmin/datasource-customizer/dist/decorators/operators-emulate/collection.js:92:61)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async ConditionTreeLeaf.replaceLeafsAsync (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/interfaces/query/condition-tree/nodes/leaf.js:56:24)
    at async OperatorsEmulateCollectionDecorator.refineFilter (/usr/src/app/node_modules/@forestadmin/datasource-customizer/dist/decorators/operators-emulate/collection.js:62:28)
    at async OperatorsEmulateCollectionDecorator.list (/usr/src/app/node_modules/@forestadmin/datasource-toolkit/dist/src/decorators/collection-decorator.js:46:31)
===================================

Expected behavior

it should open the action form and hamdle it. This error shows only fo few users not for all.

Context

I commented some code to look for exactly from where the error comes from but still getting the error.
Here is the code of action:

collection.addAction("Ajouter une transaction", {
      scope: "Single",
      form: [
        {
          label: "Amount",
          type: "Number",
          isRequired: true,
        },
        {
          label: "Comment",
          type: "String",
          widget: "TextArea",
        },
        {
          label: "Mode",
          type: "Enum",
          enumValues: ["CB", "CESU chèque", "Virement bancaire", "CESU digi.", "AI"],
        },
        {
          label: "Statut",
          type: "Enum",
          enumValues: ["Réussi ✅", "Echoué ❌", "Remboursé ↩︎"],
          defaultValue: "Réussi ✅",
        },
        {
          label: "Date",
          type: "Date",
        },
        {
          label: "PR",
          type: "Enum",
          enumValues: async context => {
            return []
            const user = await context.getRecord(['id']);
            console.log("** LOG ***", typeof user.id)
            const prs = await context.dataSource.getCollection("c_user_program_r").list({
              conditionTree: {
                field: "tutee_id", operator: 'Equal', value: user.id as number
              }
            }, ['p_visio', 'niveau', 'id']);
            return prs.map(
              (p) =>
                `${p.p_visio == "visio" ? "V" : "P"} / ${p.niveau == "Avant Bac" ? "Bac" : "Sup"
                } (${p.id})`
            );
          },
          // defaultValue: async context => {
          //   const user = await context.getRecord(['id']);
          //   const prs = await context.dataSource.getCollection("c_user_program_r").list({
          //     conditionTree: {
          //       field: "tutee_id", operator: 'Equal', value: user.id as number
          //     }
          //   }, ['p_visio', 'niveau', 'id']);
          //   if (prs.length == 1) return `${prs[0].p_visio == "visio" ? "V" : "P"} / ${prs[0].niveau == "Avant Bac" ? "Bac" : "Sup"
          //     } (${prs[0].id})`
          //   return null
          // }
        },
      ],
      async execute(context, resultBuilder) {
        const user_id = Number(await context.getRecordId() as string)
        const amount = context.formValues["Amount"];
        let comment = context.formValues["Comment"];
        let mode = context.formValues["Mode"];
        const stripe_id = mode =='CB' ? (await context.getRecord(['customer_id'])).customer_id : null
        let status = context.formValues["Statut"];
        let pr = context.formValues["PR"];
        let created_at = (new Date()).toDateString();
        let [_, program_r_id] = pr?.split("(") || [null, null];
        program_r_id = program_r_id ? program_r_id.trim().slice(0, -1) : null;
        context.dataSource.getCollection("c_user_transactions").create([{
          user_id,
          amount,
          comment,
          mode,
          status,
          program_r_id,
          created_at,
          stripe_id
        }])
console.log("add transaction ...");

        const pr_record= await context.dataSource.getCollection("c_user_program_r").list({
          conditionTree: {
            field: "id", operator: 'Equal', value: Number(program_r_id)
          }
        }, ['p_montant_pack_mois', 'p_volume_horaire_hebdo', 'credit']);
      
          if(pr_record[0].p_montant_pack_mois == amount){
            await context.dataSource.getCollection("c_user_program_r").update({
              conditionTree: {
                field: "id", operator: 'Equal', value: Number(program_r_id)
              }
            }, {
              credit: pr_record[0].credit + pr_record[0].p_volume_horaire_hebdo*4
            })
        }else if (amount > pr_record[0].p_montant_pack_mois){
            let raw_credit = amount  * pr_record[0].p_volume_horaire_hebdo*4 /pr_record[0].p_montant_pack_mois;
            let credit_to_add = Math.round(raw_credit * 4) / 4; // Rounds to nearest 0.25
          await context.dataSource.getCollection("c_user_program_r").update({
            conditionTree: {
              field: "id", operator: 'Equal', value: Number(program_r_id)
            }
          }, {
            credit: pr_record[0].credit + credit_to_add
          })

        }
      
  
        resultBuilder.success("Transactions created succefully");
  
      },
    })
  • Project name: clevermate v2
  • Environment name: Test
  • Database type: postgres

And, if you are self-hosting your agent:

  • Agent technology: (nodejs,
  • Agent (forest package) name & version (from your .lock file): … “@forestadmin/agent”: “^1.58.3”,

Hi @Adel_de_Clevermate ,

Thanks for the detailed report !
To sum things up:

  • the error occurs on the form load hook
  • from the code of your action, the errors comes from the “PR” field, where you build a filter on “tutee_id”.
  • The error message says that “tutee:id” expects a number, although you sent a number

I see that you logged the type of user.id in the field computation, does it ever returns something else than “number” ?
you cast the user.id as a number, have you tried to use parseInt(user.id) to actually ensure that you send a number ?

You say that the error is shown only to a few users, if by users you mean records from which you triggered the action, can you share an example of users that works and users that don’t (with hidden sensitive field values, of course) ?