How to Fix a Suitelet Button That Cannot Add Sublist Rows

Change a fixed-row LIST sublist to INLINEEDITOR, check the linked client handler and verify two distinct rows in the open form.

The quick answer

A LIST sublist has a fixed row count. For a client button that adds rows, create the Suitelet sublist as INLINEEDITOR, reload the form, then use selectNewLine, setCurrentSublistValue and commitLine. An exported button function can explicitly load N/currentRecord and call get; it does not receive an entry-point context automatically.

Client Sublist Check starts with an empty Rows sublist. Populate Rows tries to add A100 with quantity 2 and B200 with quantity 5. The first form uses LIST and the append fails. Changing the Suitelet type lets the same client code add both rows.

This is a local reproduction of a small Suitelet tested in an authenticated NetSuite account. The code editor's Save updates the local example source. Updating a real Suitelet file in an account is a separate deployment step. The two rows shown here are unsaved browser form data.

Before you start

The Suitelet and its linked client custom module already exist. The Suitelet creates the form and attaches suitelet_rows_client.js through form.clientScriptModulePath. Its Populate Rows button calls the exported populateRows function. The Rows sublist has a TEXT field, custpage_sku, and an INTEGER field, custpage_quantity.

Use an account and role where you can test the Suitelet and update its source through your normal deployment process. This lesson changes the sublist type; it does not walk through creating a script record or deployment. The example has no Submit button or database persistence implementation.

1. Check the fixed-row failure

Open Client Sublist Check. Sublist Type says LIST and Rows is empty. Click Populate Rows. The example catches the append failure and displays Client Line Error through N/ui/dialog.

This is the error observed in the test; its wording is not universal.

The test returned TypeError: Cannot read properties of undefined (reading '0'). That message alone does not identify the cause of every similar error. Here, the server-side type and the successful comparison with INLINEEDITOR establish the constraint. Close the dialog with OK.

2. Check the linked client handler

Open suitelet_rows_client.js in the local editor. The custom module explicitly loads N/currentRecord. Inside populateRows, currentRecord.get retrieves the active form record. That call succeeds in this test; the later attempt to append to LIST fails.

A directly called button function explicitly obtains its current record.

The loop selects a new custpage_rows line, sets its SKU and quantity, then commits it. It reads row.sku and row.quantity for each iteration. A100 and B200 are strings; quantities 2 and 5 are numbers. Repeating array element zero would repeat the first item.

At the bottom, the module returns populateRows under the same name used by the Suitelet button. A function that exists only inside the module and is never exported cannot be called through that button name.

The exported name matches the button functionName.

3. Change the server-side sublist type

Return to suitelet_rows.js. Replace LIST with INLINEEDITOR in the type assignment, then Save:

const type = serverWidget.SublistType.INLINEEDITOR;
The type variable is passed to form.addSublist.

Keep the sublist ID, field IDs, linked module path and client function unchanged. The target fields must also be editable; changing the sublist type does not make disabled fields writable. The form field that displays Sublist Type is a label added for this example; it is not a standard NetSuite setting. The local Save does not upload or deploy anything to your account.

4. Reload the generated form and populate it

Reopen Client Sublist Check after the source change. A Suitelet builds the form on the server, so editing its source does not replace the sublist already open in the browser. The rebuilt form says INLINEEDITOR and shows a blank inline row with Add and Cancel controls.

The rebuilt form provides an inline row-entry surface.

Click Populate Rows once. The same client function reports two rows in the current form. This is a message authored by the example, not a NetSuite database-save confirmation. Close it with OK.

5. Verify both rows

Check that the SKU column contains A100 and B200. Both rows must be present; one repeated item would not prove the loop used each input row.

Open the full image to compare the SKU and Quantity columns together.

The matching quantities are 2 and 5. They came from the numeric values passed to the INTEGER field.

The first row has quantity 2; the second has quantity 5.

These lines exist only in the open form. The example does not submit them or save a transaction or custom record. Reloading reconstructs an empty form.

Common questions

Is every LIST sublist read-only?

No. LIST fixes the number of rows. A field configured with FieldDisplayType.ENTRY can allow edits to an existing LIST row. It does not add a new-line workflow. STATICLIST is the read-only type.

Do I need context.currentRecord instead of currentRecord.get?

Client Script entry points such as fieldChanged receive a context object with currentRecord. The directly exported button function in this custom module receives no entry-point context. It explicitly loads N/currentRecord and calls get. Changing that call would not make a fixed-row LIST appendable.

Will forceSyncSourcing fix the append?

It can address timing while dependent fields are sourced. It does not change the sublist type or its row structure. This example uses simple text and numeric fields without dependent sourcing.

Can I keep LIST instead?

Yes, when the Suitelet should build a fixed result list on the server. Populate those rows server-side while constructing the form. Use ENTRY display type for fields that users should edit in existing rows. This walkthrough demonstrates client-side append behavior and does not implement that alternative.

Does commitLine save a record?

It commits the current line to the open form. Processing or persisting Suitelet data requires a separate submission control and a server-side handler that reads, validates and processes the lines. Neither is part of this example. Navigating away or reloading discards these unsaved rows.

Sources

The original discussion includes the author's confirmed type correction. Oracle documents sublist types and editable LIST cells, current record access and on-demand client module attachment.