# Manifest v5 "The command “Make” is not currently available"

**URL:** <https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805>\
**Category:** UXP Plugin API\
**Tags:** uxp, api-feedback\
**Created:** [December 8, 2024, 7:53pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805 "2024-12-08T19:53:24Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 8, 2024, 7:53pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/1 "2024-12-08T19:53:24Z")

</div>

So I finally got my hands on migration from manifest v4 to v5 (been using API v2 since the beginning, but not new manifest). Seemed fine at first, but ended up spending a whole day just to find, that getters (which don’t even remotely change Ps state) also need to be inside `executeAsModal()`

Is that true or am I missing something?

This script runs perfectly fine from conslole, but when I put it into a plugin on button click it doesn’t work any more:

```js
const photoshop = require("photoshop")

const layerId = await photoshop.action.batchPlay([{
    "_obj": "get",
    "_target": [
        { "_property": "targetLayersIDs" },
        { "_ref": "document", "_enum": "ordinal", "_value": "targetEnum" },
    ],
}], {
    synchronousExecution: true,
    modalBehavior: "execute",
})[0]["targetLayersIDs"][0]["_id"]

const rs = await photoshop.core.executeAsModal(async (executionContext) => {
    let suspensionID
    const hostControl = executionContext.hostControl

    suspensionID = await hostControl.suspendHistory({
        historyStateInfo: {
            name: "HISTORY",
            target: [{
                _ref: "document",
                _id: photoshop.app.activeDocument.id,
            }],
        },
    })

    await photoshop.action.batchPlay([
        {
            "_obj": "select",
            "_target": [{ "_ref": "layer", "_id": layerId }],
            "makeVisible": false,
        },
        {
            "_obj": "select",
            "_target": [{ "_ref": "channel", "_enum": "channel", "_value": "mask" }],
        },
        {
            "_obj": "delete",
            "_target": [{ "_ref": "channel", "_enum": "ordinal", "_value": "targetEnum" }],
        },
        {
            "_obj": "select",
            "_target": [{ "_ref": "layer", "_id": layerId }],
            "makeVisible": false,
        },
    ], {
        synchronousExecution: true,
        modalBehavior: "execute",
    })

    await photoshop.action.batchPlay([
        {
            "_obj": "select",
            "_target": [{ "_ref": "layer", "_id": layerId }],
            "makeVisible": false,
        },
        {
            "_obj": "make",
            "new": { "_class": "channel" },
            "at": { "_ref": "channel", "_enum": "channel", "_value": "mask" },
            "using": { "_enum": "userMaskEnabled", "_value": "hideAll" },
        },
        { "_obj": "select", "_target": [{ "_ref": "layer", "_id": layerId }], "makeVisible": false },
    ], {
        synchronousExecution: true,
        modalBehavior: "execute",
    })

    hostControl.resumeHistory(suspensionID)
}, { commandName: "COMMAND NAME" })

```

In a nutshell:

- It gets selected layer
- Tries to delete a mask if it’s there
- Tries to create a new black mask on that layer
- Reselects the layer

As mentioned, from console it works every time.  
If I put it into a plugin, I get these errors on two BatchPlays inside `executeAsModal()`:

```js

BpErr1 = { // From the first chunk of descriptors (delete mask)
    "message": "My plugin: The command “Select” is not currently available.",
    "failedDescriptor": {
        "_obj": "select",
        "_target": [
            { "_ref": "channel", "_enum": "channel", "_value": "mask" },
        ],
    },
}

BpErr2 = { // From the second chunk of descriptors (create mask)
    "message": "My plugin: The command “Make” is not currently available.",
    "failedDescriptor": {
        "_obj": "make",
        "new": { "_class": "channel" },
        "at": { "_ref": "channel", "_enum": "channel", "_value": "mask" },
        "using": { "_enum": "userMaskEnabled", "_value": "hideAll" },
    },
}

```

What I found after hours and hours of debugging, that if I move this part:

```js
const layerId = await photoshop.action.batchPlay([{
    "_obj": "get",
    "_target": [
        { "_property": "targetLayersIDs" },
        { "_ref": "document", "_enum": "ordinal", "_value": "targetEnum" },
    ],
}], {
    synchronousExecution: true,
    modalBehavior: "execute",
})[0]["targetLayersIDs"][0]["_id"]

```

inside the same `executeAsModal()` a bit lower, it starts working fine…

At some point I tried just setting manifest version back to `4`, but that didn’t help and the only thing I changed, was `panels` part in `entrypoints.setup()`. Also noticed, that even with getter outside execModal maybe once in 50 times it creates a mask (if there’s a mask already, it deletes every time)

What’s the deal? 🫠

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 9, 2024, 10:17am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/2 "2024-12-09T10:17:12Z")

</div>

So I was going through [this 2.5 yars old thread](https://forums.creativeclouddeveloper.com/t/move-layer-to-front-through-batch-play-works-differently-in-ps-23-4-1/4814/17) and it seems it’s the exact same issue I’m having and there’s no solution 😞 Looks like I’m gonna have to stay on manifest v4 for the time being… Unfortunately this prevents further development of the plugin

I’ll try a bit more of just guessing things and seeing if something works, but I’m pretty hopeless now

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 9, 2024, 10:38am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/3 "2024-12-09T10:38:39Z")

</div>

Or I think I’ll just move this:

```auto
const layerId = await photoshop.action.batchPlay([{
    "_obj": "get",
    "_target": [
        { "_property": "targetLayersIDs" },
        { "_ref": "document", "_enum": "ordinal", "_value": "targetEnum" },
    ],
}], {
    synchronousExecution: true,
    modalBehavior: "execute",
})[0]["targetLayersIDs"][0]["_id"]

```

into the same execModal, which seems the only way that makes script work, but doesn’t really make sense, because it doesn’t work only for mask creation (mask delete and other state changing actions work fine with `targetLayersIDs` getter outside execModal)

I believe there’s something still broken with this since Ps v23.4.1  
Not sure whom to ping 😕 @Erin_Finnegan, could you please jump in?

---

<div class="post-metadata">

**Author:** ![Erin\_Finnegan](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/erin_finnegan/32/100_2.png) [@Erin\_Finnegan](https://forums.creativeclouddeveloper.com/u/Erin_Finnegan)\
**Post date:** [December 9, 2024, 6:03pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/4 "2024-12-09T18:03:04Z")

</div>

I mean we can ping @indranil and @samgannaway, perhaps?

---

<div class="post-metadata">

**Author:** ![photonic](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/photonic/32/2513_2.png) [@photonic](https://forums.creativeclouddeveloper.com/u/photonic)\
**Post date:** [December 9, 2024, 6:05pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/5 "2024-12-09T18:05:37Z")

</div>

I literally copied and pasted your code into a button click function or even outside just when the plugin loads. it works without any errors.

This is my manifest maybe something here helps?

```auto
{
  "id": "ONIRICUXP",
  "name": "Oniric v2.3.0 (UXP)",
  "version": "2.3.0",
  "main": "index.js",
  "host": [
    {
      "app": "PS",
      "minVersion": "23.0.0",
      "data": {
        "apiVersion": 2,
        "loadEvent": "use"
      }
    }
  ],
  "requiredPermissions": {
    "localFileSystem": "fullAccess",
    "launchProcess": {
      "extensions": [
        ""
      ],
      "schemes": [
        "https"
      ]
    },
    "network": {
      "domains": "all"
    },
    "allowCodeGenerationFromStrings": true
  },
  "manifestVersion": 5,
  "entrypoints": [
    {
      "type": "panel",
      "id": "oniricUXP",
      "minimumSize": {
        "width": 260,
        "height": 300
      },
      "maximumSize": {
        "width": 1000,
        "height": 1920
      },
      "preferredDockedSize": {
        "width": 260,
        "height": 1010
      },
      "preferredFloatingSize": {
        "width": 260,
        "height": 1010
      },
      "label": {
        "default": "Oniric v2.3.0 (UXP)"
      },
      "icons": [
        {
          "width": 23,
          "height": 23,
          "path": "icons/oniric.png",
          "scale": [
            1,
            2
          ],
          "theme": [
            "dark",
            "darkest",
            "medium",
            "light",
            "lightest",
            "all"
          ]
        }
      ]
    }
  ],
  "icons": [
    {
      "width": 48,
      "height": 48,
      "path": "icons/on.png",
      "scale": [
        1,
        2
      ],
      "theme": [
        "darkest",
        "dark",
        "medium",
        "lightest",
        "light"
      ],
      "species": ["pluginList"]
    }
  ],
  "runOnStartup": true
}

```

---

<div class="post-metadata">

**Author:** ![Erin\_Finnegan](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/erin_finnegan/32/100_2.png) [@Erin\_Finnegan](https://forums.creativeclouddeveloper.com/u/Erin_Finnegan)\
**Post date:** [December 9, 2024, 6:15pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/6 "2024-12-09T18:15:05Z")

</div>

Thanks, @photonic ! 🙌

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 9, 2024, 6:20pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/7 "2024-12-09T18:20:36Z")

</div>

I’m now going step by step to see what exactly I’ve changed in my code. I did Node modules update almost all to latest versions and did quite a bit of refactoring, which was exclusively only moving files/folders. I didn’t change any code at all, but clearly something broke ☹

Will definitely let you know when/if I find something. I’m literally now trying to move in very small steps and after each step check if it still works or not. Might take a while… 😞

---

<div class="post-metadata">

**Author:** ![Wanokuni](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/wanokuni/32/2203_2.png) [@Wanokuni](https://forums.creativeclouddeveloper.com/u/Wanokuni)\
**Post date:** [December 9, 2024, 8:16pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/8 "2024-12-09T20:16:15Z")

</div>

Here’s my version of what you’re likely trying to achieve. I wrap every function I use and execute it as a model, as I’ve found that with version 5, most Photoshop functionalities require it.

```auto

 const app = require("photoshop").app;
 const batchPlay = require("photoshop").action.batchPlay;
const ExecuteAsModal = require("photoshop").core.executeAsModal;

function getSelectedLayerInfo() {
  if (!app.activeDocument) {
    console.warn("No active document found.");
    return [];
  }

  // Retrieve the names and IDs of selected layers
  return app.activeDocument.layers
    .filter((layer) => layer.selected) 
    .map((layer) => ({
      id: layer.id, // Layer ID
      name: layer.name, 
    })); 
}
 

async function checkAndDeleteLayerMask(layerId, documentId) {
  // check if active layer has a layer mask
  const result = await batchPlay(
    [
      {
        _obj: "get",
        _target: [
          {
            _property: "hasUserMask",
          },
          {
            _ref: "layer",
            _id: layerId,
          },
          {
            _ref: "document",
            _id: documentId,
          },
        ],
        _options: {
          dialogOptions: "dontDisplay",
        },
      },
    ],
    {}
  );

  const hasLayerMask = result[0].hasUserMask;
  console.log("hasUserMask?", hasLayerMask);

  if (hasLayerMask === true) {
    await deleteChannel();
  }

}

// add layer mask Black = "hideAll" / white mask "revealAll"
async function makeMask(mask) {
  const makeLayerMask = {
    _obj: "make",
    at: {
      _enum: "channel",
      _ref: "channel",
      _value: "mask",
    },
    new: {
      _class: "channel",
    },
    using: {
      _enum: "userMaskEnabled",
      _value: mask,
    },
  };
  await batchPlay([makeLayerMask], {});
}

async function FunctionsX(executionContext) {
  if (app.documents.length == 0) {
    app.showAlert("Please open at least one document.");

    return;
  }
  let hostControl = executionContext.hostControl;
  let suspensionID = await hostControl.suspendHistory({
    documentID: app.activeDocument?.id,
    name: "History",
  });

  try {
    const selectedLayerInfo = getSelectedLayerInfo();
    console.log("Selected Layer Info:", selectedLayerInfo);

    if (selectedLayerInfo.length > 0) {
      await selectLayer({ id: selectedLayerInfo[0].id });
    } else {
      console.log("No layers selected.");
    }

    await checkAndDeleteLayerMask(
      app.activeDocument.activeLayers[0]._id,
      app.activeDocument?.id
    );

  makeMask("hideAll");

    await hostControl.resumeHistory(suspensionID);
  } catch (error) {
    console.log(error);
 
  }
}

document
  .getElementById("SlectLayer")
  .addEventListener("click", async function () {
    await ExecuteAsModal(FunctionsX, {
      commandName: "Fucntions X command",
    });

  });

```

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 9, 2024, 8:20pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/9 "2024-12-09T20:20:09Z")

</div>

> [@Wanokuni](#):
>
> with version 5, most Photoshop functionalities require it

Yep, but only those, which change the state. Getting selected layers doesn’t require that 😕 I’m still trying to find the exact moment it stops working while re-refactoring

---

<div class="post-metadata">

**Author:** ![AnthonyK](https://avatars.discourse-cdn.com/v4/letter/a/85f322/32.png) [@AnthonyK](https://forums.creativeclouddeveloper.com/u/AnthonyK)\
**Post date:** [December 9, 2024, 8:26pm UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/10 "2024-12-09T20:26:11Z")

</div>

I’m using `"manifestVersion": 5,` in my manifest.json and the following getter code does NOT require executeAsModal:

```auto
let selection = await batchPlay([
//Check to see if there is a selection
{ _obj: "multiGet", _target: {_ref: "document", _enum: "ordinal", _value: "targetEnum"}, extendedReference: [["selection"]], "_options": { "dialogOptions": "silent" }}], {})
```

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 10, 2024, 1:13am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/11 "2024-12-10T01:13:59Z")

</div>

🤦‍♂️ 🤦‍♂️ 🤦‍♂️

So I used to have this (full `execModal()` function):

```auto
export const execModal = async (
    func, { commandName, historyState },
) => {
    return photoshop.core.executeAsModal(async (executionContext) => {
        let suspensionID
        const hostControl = executionContext.hostControl

        if (historyState && photoshop.app.activeDocument) {
            suspensionID = await hostControl.suspendHistory({
                historyStateInfo: {
                    name: historyState,
                    target: [{
                        _ref: "document",
                        _id: photoshop.app.activeDocument.id,
                    }],
                },
            })
        }

        await func()

        if (historyState && photoshop.app.activeDocument) {
            hostControl.resumeHistory(suspensionID)
        }

        return
    }, { commandName })
}

```

After refactoring I changed the `if history part` to this:

```auto
        if (historyState && photoshop.app.activeDocument) {
            suspensionID = await hostControl.suspendHistory({
                historyStateInfo: {
                    name: historyState,
                    target: [{
                        _ref: "document",
                        _id: photoshop.app.activeDocument.id,
                    }],
                },
            })

            await func()
            hostControl.resumeHistory(suspensionID)
        } else {
            func()
        }

```

Lost the `await` on `func()` call when without history suspension…

So what happens is, when I click the button, for whatever reason I get two calls to `execModal()` - first one without history suspension (I assume it’s some getter maybe) and the next one with suspension (the mask delete and create). Before the first one finishes, second one executes and fails…

Will need to find out why there are two calls to `execModal()` in my code. Any ideas how to trace back where from I’m calling it?

But now it’s 3AM and time to get some sleep 😔

---

<div class="post-metadata">

**Author:** ![Jarda](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/jarda/32/1909_2.png) [@Jarda](https://forums.creativeclouddeveloper.com/u/Jarda)\
**Post date:** [December 10, 2024, 9:12am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/12 "2024-12-10T09:12:31Z")

</div>

This can save you a lot of hair: [no-floating-promises | typescript-eslint](https://typescript-eslint.io/rules/no-floating-promises/) 😃

I set the es-lint to check before build and make build fail if there is floating promise.

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 10, 2024, 10:04am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/13 "2024-12-10T10:04:51Z")

</div>

Nice 🙂 Noticed in the docs some things I might benefit from so I updated my config, but it seems I already had everything covered. It’s just that the callback `func` in my case may be both async and not, so it doesn’t trigger the error ☹ But I guess to be safe, if I’m inside async funcion, to almost always add `await` as it will instantly resolve anyway 😃

---

<div class="post-metadata">

**Author:** ![Karmalakas](https://sea1.discourse-cdn.com/flex015/user_avatar/forums.creativeclouddeveloper.com/karmalakas/32/1048_2.png) [@Karmalakas](https://forums.creativeclouddeveloper.com/u/Karmalakas)\
**Post date:** [December 10, 2024, 10:13am UTC](https://forums.creativeclouddeveloper.com/t/manifest-v5-the-command-make-is-not-currently-available/8805/14 "2024-12-10T10:13:48Z")

</div>

> [@Karmalakas](#):
>
> Will need to find out why there are two calls to `execModal()` in my code

If anyone is interested, I had nested `execModal()` calls and it was something like:

```plaintext
execModal( without_history_suspension )
|- getSelectedLayers()
'- execModal( with_history_suspension )
   |- deleteMask()
   '- createMask()

```
