ARTICLE AD BOX
The reason you are experiencing this issue is due to a known architectural anti-pattern in Next.js: calling a Server Action from within another Server Action.
The Root Cause
Both actions.ts and DropDownServices.ts contain the 'use server' directive. In Next.js, this directive tells the compiler to treat the file as a boundary and wrap every exported function in a special RPC proxy (an internal dispatcher) meant only to be called over HTTP from a Client Component.
When your Client Component calls getDropDownList (Action A), which then internally calls get (Action B), you are crossing Server Action boundaries on the server. Nesting them confuses React's internal request context and AsyncLocalStorage.
The first call might execute successfully, but Action B often corrupts or prematurely tears down the dispatcher that Action A is relying on. This leaves the internal request state broken, causing your second invocation to deadlock or hang indefinitely. This perfectly matches your symptom: the nested promise hangs, your Axios endpoint is never reached, and the client receives no response on the second try.
The Solution
To fix this, you need to decouple your core logic from your Server Action entry points. The recommended pattern is to extract the Axios fetch logic into a standard, non-action utility function and import that into your Server Action files.
Here is how you can refactor your code:
1. Create a core utility file (e.g., api-utils.ts)
Do not add the 'use server' directive here. This is a standard asynchronous Node.js function for your server-side business logic.
// api-utils.ts // (Import your request, HttpMethod, getDecryptedToken, etc. here) export async function fetchWithAxios<T>( url: string, params?: Service.IParams ): Promise<T> { let result = request<T>(HttpMethod.GET, url, { params, headers: setupHeaders(await getDecryptedToken()) }); return result; }2. Update actions.ts
Keep the 'use server' directive so the client can still hit it, but delegate the actual work to your new utility function.
// actions.ts 'use server' import { fetchWithAxios } from './api-utils'; export async function get<T>( url: string, params?: Service.IParams ): Promise<T> { // Acts as a clean Server Action wrapper for direct client calls return await fetchWithAxios<T>(url, params); }3. Update DropDownServices.ts
Import the utility function instead of the Server Action.
// DropDownServices.ts 'use server' import { fetchWithAxios } from './api-utils'; // <-- Import the raw function let urlKeyValueMap = new Map<string, string>(); urlKeyValueMap.set("query1", "/lookup/query1"); urlKeyValueMap.set("query2", "/lookup/query2"); export async function getDropDownList<T>(urlKey: string): Promise<T>{ let url = urlKeyValueMap.get(urlKey); if(url) { // Now calling a standard server function, completely avoiding the action deadlock let result = await fetchWithAxios<any>(url); return result; } else { return [] as any; } }Defining let urlKeyValueMap = new Map() at the module level outside of a function is perfectly fine if the map is strictly static. However, be aware that if you deploy to a serverless environment, module-level memory isn't shared across different function instance executions and can be reset. If you ever plan to mutate that map dynamically during runtime, you'll want to move that state to a database or a caching layer like Redis.
