Why Won't My NetSuite Custom Button Call Its Client Script?

Check the attached client module and button functionName, then return the named handler from the Client Script module.

The quick answer

When the attached client module loads successfully, a custom button's functionName must match a property returned by that module. A function declaration alone is insufficient. In this example, the attachment and name are already correct; adding checkHandler to the returned object repairs the missing export.

This walkthrough uses a fictional invoice, local code editor and API harness. The invoice button reads the same saved client source. Its in-page browser-alert stand-in shows the handler result. No File Cabinet upload, NetSuite deployment or production execution is verified.

Before you start

For account use, confirm that the User Event deployment applies to the intended record, user and event. This example adds its button only in View. A User Event deployment in Testing runs only for the script owner. When it is Released, check its audience and other deployment settings; audience does not broaden Testing execution. For account execution, confirm that the client file is accessible in the NetSuite File Cabinet at the path relative to the deployed User Event script file. Here both files occupy the same prepared local folder.

Oracle documents Form.addButton and Form.clientScriptModulePath. Attach a client file through clientScriptModulePath or clientScriptFileId; do not set both. Keep any required existing module exports when adding a handler.

01. Inspect the button

Open INV-8127 for Summit Repair Solutions in View. Check Handler is already present, and the invoice total is 126.00. Button placement varies with the form and its other actions. Seeing the button confirms that the form contains it; it does not establish that its handler can be resolved.

The existing invoice has a Check Handler button before the client repair.

02. Check the attachment

Open the read-only invoice_button_ue.js preview. Its VIEW-only beforeLoad attaches ./invoice_button_client.js and adds the button with functionName: 'checkHandler'. These values establish which module and exported property to inspect next.

function beforeLoad(context) {
  if (context.type !== context.UserEventType.VIEW) {
    return;
  }
  context.form.clientScriptModulePath =
    './invoice_button_client.js';
  context.form.addButton({
    id: 'custpage_check_handler',
    label: 'Check Handler',
    functionName: 'checkHandler'
  });
}
The User Event attaches the client file by its relative module path.

03. Find the missing export

Return to invoice_button_client.js. The file defines pageInit and checkHandler, but returns only pageInit. Click Run local harness. Its diagnostic says exported function checkHandler not found. This is the local module checker’s message, not a promised NetSuite exception or execution log.

The local harness cannot find checkHandler in the returned module.

04. Return the handler

Add checkHandler to the returned object while preserving pageInit. The repaired client source is:

/**
 * @NApiVersion 2.1
 * @NScriptType ClientScript
 */
define([], () => {
  function pageInit() {}
  function checkHandler() {
    console.log('Handler reached');
    window.alert('Handler reached');
  }
  return {pageInit, checkHandler};
});

Click Save, then Run local exercise. The harness resolves the exported handler and reports its console and browser-alert model output. It also applies those saved bytes to the local invoice example. The empty pageInit is retained as an existing entry point. pageInit does not run in View mode; the exported custom handler can still be invoked by the View-mode button.

Return checkHandler alongside the existing pageInit export.

05. Click the repaired button

Reopen the invoice in View and click Check Handler. Handler reached appears in the in-page stand-in for window.alert. This confirms that the local form resolved the named exported handler from the saved source.

The local button reaches its handler and displays Handler reached.

06. Confirm after reload

Click OK, reload the invoice, and click Check Handler again. Confirm the same message, then dismiss it. The observed invoice total remains 126.00. This checks retained local source wiring; account deployment, browser caching and role behavior need their own account checks.

The same local handler confirmation appears after a fresh invoice load.

Common questions

Is defining the function enough?

No. The module must return a property matching the button's functionName. Check spelling and case. If attachment or module loading fails, fix that first; if the exported function runs and then throws, inspect the handler body separately.

Does every attached client file need its own deployment?

A form-attached client module can be loaded through the User Event's clientScriptModulePath. The recording uses that route and does not create a separate Client Script deployment. The server script's applicable deployment and the client file's path still matter.

Where should I look for logs?

console.log writes to the browser console. For a client module attached through clientScriptModulePath or clientScriptFileId, N/log entries can be associated with the parent script deployment. A missing browser-console message, N/log entry or local diagnostic cannot by itself distinguish attachment failure, module-load failure, an unresolved export or an exception inside the handler.

Will record.create open a custom record entry form?

record.create() creates an unsaved in-memory record object. It does not open a browser form or save the record. A custom record type uses a customrecord_ identifier, while custrecord_ identifies a custom field. Those are separate handler-body concerns. This example only displays a confirmation and does not create, save or navigate to a record.