Image Load fails to parse dynamic expressions in path (Input file is missing)

I am struggling with the Image Load module in a Node.js project. It seems that dynamic expressions in the path field are not being parsed correctly inside a repeat loop.

The Issue: When I use the standard {{path}} or {{$value.path}}, I get: "image.load: path is required."

When I try to construct the path manually to bypass the scope issue, for example: '/public/assets/banner/test/' + $name or '/public/assets/banner/test/' + name

The debugger shows that Wappler tries to load the literal string "name" instead of the variable value: Error: Input file is missing: C:\...\public\assets\banner\test\name

Context:

  • The files are physically present in the folder.

  • The upload step before the repeat is successful.

  • It appears the Expression Handler is not resolving variables inside the Image Load "path" input.

{
  "meta": {
    "options": {
      "linkedFile": "/views/web-admin/images.ejs",
      "linkedForm": "form_image_upload"
    },
    "$_POST": [
      {
        "type": "text",
        "fieldName": "assigned_id",
        "name": "assigned_id"
      },
      {
        "type": "text",
        "fieldName": "assigned_type",
        "name": "assigned_type"
      },
      {
        "type": "text",
        "fieldName": "is_partner",
        "name": "is_partner"
      },
      {
        "type": "file",
        "fieldName": "image_file",
        "multiple": true,
        "options": {
          "rules": {
            "upload:accept": {
              "param": "image/*"
            }
          }
        },
        "name": "image_file",
        "sub": [
          {
            "name": "name",
            "type": "text"
          },
          {
            "name": "type",
            "type": "text"
          },
          {
            "name": "size",
            "type": "number"
          },
          {
            "name": "error",
            "type": "text"
          }
        ],
        "outputType": "array"
      }
    ]
  },
  "exec": {
    "steps": [
      {
        "name": "multi_image_upload",
        "module": "upload",
        "action": "upload",
        "options": {
          "fields": "{{$_POST.image_file}}",
          "template": "{name}{ext}",
          "overwrite": true,
          "path": "/public/assets/banner/test"
        },
        "meta": [
          {
            "name": "name",
            "type": "text"
          },
          {
            "name": "path",
            "type": "text"
          },
          {
            "name": "url",
            "type": "text"
          },
          {
            "name": "type",
            "type": "text"
          },
          {
            "name": "size",
            "type": "text"
          },
          {
            "name": "error",
            "type": "number"
          }
        ],
        "outputType": "array",
        "output": true
      },
      {
        "name": "repeat",
        "module": "core",
        "action": "repeat",
        "options": {
          "outputFields": [],
          "repeat": "{{multi_image_upload}}",
          "exec": {
            "steps": {
              "name": "image",
              "module": "image",
              "action": "load",
              "options": {
                "path": "{{path}}"
              },
              "outputType": "object",
              "meta": [
                {
                  "name": "width",
                  "type": "number"
                },
                {
                  "name": "height",
                  "type": "number"
                }
              ]
            }
          }
        },
        "output": true,
        "meta": [
          {
            "name": "$index",
            "type": "number"
          },
          {
            "name": "$number",
            "type": "number"
          },
          {
            "name": "$name",
            "type": "text"
          },
          {
            "name": "$value",
            "type": "object"
          },
          {
            "name": "name",
            "type": "text"
          },
          {
            "name": "path",
            "type": "text"
          },
          {
            "name": "url",
            "type": "text"
          },
          {
            "name": "type",
            "type": "text"
          },
          {
            "name": "size",
            "type": "text"
          },
          {
            "name": "error",
            "type": "number"
          }
        ],
        "outputType": "array"
      }
    ]
  },
  "usedModules": {
    "sharp": "^0.29.3"
  }
}

What does the path return if you disable the load image step and use set value to output its value?

nothing…

Have you selected any output fields in the repeat step then?

I see nothing wrong in your setup and code.
The same steps work perfectly fine in my setup. Have you tried recreating the server action?

Yes, this is already a new query for testing.

What is the front ent input you are using for the multi upload? Can you post its code here?
For some reason your upload step does not return an array, which could be caused by what you send from the front end.

You're right, there's something wrong with my upload form.

I created it with AI.

It works with a form I created myself.
Here's where the error was:
AI wrote:

name="image_file"

But it should be written like this:

name="image_file[]"

Here's the AI ​​code.

<form id="form_image_upload" is="dmx-serverconnect-form" method="post" action="/api/admin/images/upload_multi_image" enctype="multipart/form-data" dmx-on:success="notifies1.success('Bilder erfolgreich hinzugefügt!'); modal_upload_images.hide()" dmx-on:error="notifies1.danger('Fehler beim Upload: ' + lastError.response)">

                    <div class="modal-body">
                        <input type="hidden" name="assigned_id" dmx-bind:value="query.site">
                        <input type="hidden" name="assigned_type" value="site_galerie">

                        <div class="form-check form-switch mb-4">
                            <input class="form-check-input" type="checkbox" id="inp_is_partner" name="is_partner" value="1">
                            <label class="form-check-label fw-bold" for="inp_is_partner">
                                Partner-Modus (Originalformate erhalten)
                            </label>
                            <small class="d-block text-muted">Aktivieren, wenn Bilder nicht auf Slider-Maß gecroppt werden sollen.</small>
                        </div>

                        <div class="upload-area p-5 border border-2 border-dashed rounded text-center bg-light" onclick="document.getElementById('inp_image_file').click()" style="cursor: pointer; border-style: dashed !important;">
                            <i class="fas fa-images fa-3x text-primary mb-3"></i>
                            <p class="mb-0">Klicken oder Bilder hierher ziehen</p>
                            <small class="text-muted">Multi-Upload möglich (WebP, JPG, PNG)</small>

                            <input type="file" class="d-none" id="inp_image_file" name="image_file" accept="image/*" onchange="document.getElementById('file_count_display').innerText = this.files.length + ' Bilder ausgewählt'" multiple="true" data-msg-accept="">
                        </div>
                        <div id="file_count_display" class="text-center mt-2 small fw-bold text-primary"></div>
                    </div>

                    <div class="modal-footer bg-light">
                        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
                        <button type="submit" class="btn btn-primary" dmx-bind:disabled="!inp_image_file.value || form_image_upload.state.executing">
                            <span class="spinner-border spinner-border-sm me-2" role="status" dmx-show="form_image_upload.state.executing"></span>
                            Upload starten
                        </button>
                    </div>
                </form>

Why not use the dropzone component for such kind of uploads then?
there is probably some js code that breaks your form/file input.