Duplicate portfolios via Run Script rule action?

I’m trying to build a script with Claude to duplicate a portfolio (based on an existing one) using a run script rule action but it’s returning with an error that this endpoint is not supported or not exposed so we can use it.

Does anyone know if that’s indeed true or Claude is hallucinating, even though I directed it to Duplicate a portfolio and ran some tests to see what’s available.

@Mikhail_Melikhov , @Dominik_Brdak
Thanks!

If the endpoint exist, it should work, unless the nodeJS client doesn’t yet have this method.
Do you know writing scripts for portfolio rules is slightly different than before because there isn’t a triggering task? There is a container id for example

Good point, @Bastien_Siebman . I should have clarified that the rule is in a project, running on a task and the action is to create a portfolio based on a ‘placeholder’ portfolio (critically retaining it’s saved view tabs) and populating all it’s fields as per the triggered task’s values, adding it to an ‘All programs’ portfolio.

The resulting portfolio is basically a ‘program’ which will contain 4 projects (components) so the next part of the script should go on to create these 4 projects based on project templates (or duplicating placeholder projects).

My devs can do all this externally - the question is if it can be done with rule script actions within Asana.

It should, I never found anything you can’t do in Script if you can do in code.
The code is the same?
What’s the error?

Thanks, @Bastien_Siebman, same here actually. I have never come across this issue, having created many scripts so far.

FWIW, here’s Claude’s ‘summary’:

Goal: Call the POST /portfolios/{portfolio_gid}/duplicate endpoint from within a Run Script rule action.

What we tried:

  1. Called portfoliosApiInstance.duplicatePortfolio(portfolio_gid, { data: {...} }) directly, assuming it followed the same naming convention as other confirmed working methods on this instance (e.g. updatePortfolio, addItemForPortfolio).

    • Error: {"name":"TypeError","message":"not a function"}
  2. Enumerated all own properties of portfoliosApiInstance via Object.getOwnPropertyNames(portfoliosApiInstance) to see the full list of available methods.

    • Result: Exactly 12 methods, none of which is a duplicate-related method:
      addCustomFieldSettingForPortfolio, addItemForPortfolio, addMembersForPortfolio, createPortfolio, deletePortfolio, getItemsForPortfolio, getPortfolio, getPortfolios, removeCustomFieldSettingForPortfolio, removeItemForPortfolio, removeMembersForPortfolio, updatePortfolio.
  3. Checked for a lower-level API client (e.g. portfoliosApiInstance.apiClient) that might expose a generic “call any endpoint” method, in case the duplicate endpoint was reachable outside the resource-specific wrapper.

    • Result: No such object exists (portfoliosApiInstance.apiClient is undefined).
  4. Tested for any raw HTTP capability in the script sandbox — direct references (not typeof, which gives false positives on undeclared variables) to fetch, axios, request, and http.

    • Result: All four throw ReferenceError: ... is not defined. No raw HTTP client is available in this environment at all.
  5. Tested for any generic Asana SDK/client object that might expose the full API surface beyond the individual resource instances — asana, Asana, defaultApiInstance, apiInstance, httpClient, requestClient.

    • Result: All throw ReferenceError: ... is not defined.

Conclusion so far: From inside a Run Script action, we only have access to a fixed set of resource-specific API instances (tasksApiInstance, portfoliosApiInstance, projectsApiInstance, etc.), each with a limited, non-configurable method list. There’s no raw HTTP client, no generic API client, and no duplicatePortfolio-style method anywhere reachable from the script’s global scope — even though the endpoint itself is documented in the public REST API.

Question for Asana: If the endpoint is expected to work in Run Script, could you clarify the exact method name and object it should be called on (e.g. is it under a different instance than portfoliosApiInstance, or does it require an SDK version/update that isn’t currently loaded in the Run Script sandbox)?

The fact that this returns “not a function”
portfoliosApiInstance.duplicatePortfolio
means that this function duplicate doesn’t exist. That’s the source issue.

And because you found 12 methods, it means the dev team simply did not code that method yet, duplication is fairly new.

There is a way to do calls using the nodeJS client, the keyword is “dispatcher”, ask your AI to look for it. If needed I have examples, but I am really not sure it will work within Script Actions

Here is an example in my codebase

getGoals(workspaceId: string, optFields?: string): Observable<AsanaGoal[]> {
    const client = this.asanaConnectService.getClient()
    const opt_fields = 'name,gid,owner.email' + (optFields ? ',' + optFields : '')
    return from(
      Promise.resolve(
        client.dispatcher.get(`/goals`, Object.assign({ workspace: workspaceId }, { opt_fields: opt_fields })).then((data) => data)
      ).finally(() => Promise.resolve())
    ).pipe(map((res: any) => res.data.map(goal => new AsanaGoal(goal))))
  }

Thanks @Bastien_Siebman - you’re right but no luck unfortunately.. from Claude:

That confirms it fully — dispatcher isn’t reachable as a global or as a property on any of the API instances we have access to (portfoliosApiInstance, tasksApiInstance, projectsApiInstance). Combined with everything else we’ve tested (no apiClient, no raw fetch/axios/http, no generic Asana client object), the conclusion holds: the Run Script sandbox exposes only the fixed, pre-built resource instances with their fixed method lists — there’s no way to reach the underlying HTTP client or dispatcher from inside a script action in this environment.

Bastien’s client.dispatcher.get(...) pattern works in their codebase because they’re using the Asana Node SDK directly in their own application, where they instantiate and hold a reference to the full client object themselves. The Run Script sandbox, by contrast, only injects narrow, per-resource wrapper instances into the script’s scope — it deliberately (or as a current limitation) doesn’t expose the client/dispatcher that those wrappers are built on top of.

Here’s a summary:

Following up on the dispatcher suggestion: we tested for a dispatcher property on all available API instances (portfoliosApiInstance, tasksApiInstance, projectsApiInstance) as well as a bare global dispatcher. All came back undefined (confirmed via direct reference, which throws ReferenceError for truly undefined identifiers — not typeof, which can give false negatives on undeclared globals).

This, combined with our earlier findings (no apiClient/client/_apiClient object on any instance, no raw fetch/axios/http, and no generic top-level Asana client), indicates that the Run Script sandbox only exposes the specific resource-scoped API wrapper instances (with their fixed method lists) and nothing lower-level. There doesn’t appear to be any way to reach the underlying HTTP dispatcher/client from inside a script action to call an endpoint that isn’t wrapped by one of the provided instance methods (like duplicatePortfolio).

@Mikhail_Melikhov , @Dominik_Brdak , @John_Baldo

Given duplicatePortfolio isn’t implemented on portfoliosApiInstance and there’s no lower-level escape hatch, is there a roadmap for adding it to the Run Script SDK, or is there a different supported way to trigger a portfolio duplication from within a Rule’s script action?

Thank you for reporting this @Richard_Sather!

I can see that duplicatePortfolio is available in the Asana Node SDK, so we just haven’t deployed it yet to the Script Actions environment.

I will reach out internally to request that this method be added to Script Actions and update you as soon as it’s available!

Awesome, @Dominik_Brdak , thank you so much!

If you could give me please a ball park ETA on that, it would help us plan accordingly for our customer’s imminent workflow launch. :slight_smile:

@Richard_Sather I don’t want to set any false expectations, but I’m hopeful that we’ll be able to deploy the duplicatePortfolio method in Script Actions by the end of this week or early next week.

If anything changes in the meantime, I’ll post an update here on Monday, so you have visibility into our progress.

I’ll keep you posted!

AMAZING!! :folded_hands:

Just writing in appreciation of this thread and @Richard_Sather, @Bastien_Siebman, and @Dominik_Brdak’s contributions!

Hi everyone! duplicatePortfolio method is now available in Script Actions :tada:

You guys are rock stars!! :sign_of_the_horns:
Thanks so much @Dominik_Brdak , you made my weekend! :slight_smile: