---
title: "The form with no Next button"
description: "A screen flow that replaces the Lead New action had three screens with allowFinish set to false. The footer rendered, empty, and nobody could get past screen one. Why allowFinish governs the Next button too, the blank screen input that IsNull never matched, and the connector that looped back and erased everything the user had typed."
source: "https://noconaconsulting.com/blog/screen-flow-allowfinish-next-button/"
---

# The form with no Next button

_Build log · Doorvana · Garage door manufacturing & service_

A screen flow that replaces the Lead New action had three screens with allowFinish set to false. The footer rendered, empty, and nobody could get past screen one. Why allowFinish governs the Next button too, the blank screen input that IsNull never matched, and the connector that looped back and erased everything the user had typed.

Nocona Consulting · November 5, 2026 · 9 min read

The form looked finished. Every field worked. The person filling it in picked a type, typed a name, an email and a phone number, and went to move on.

There was nothing to press. The footer was there — the divider line across the bottom of the modal, the padding, the space where the buttons go — and it was empty. No Next, no Previous, no Cancel inside the flow. The lead could not be created.

That was the client’s first evening entering real builder prospects into the sandbox. The screen had been built six weeks earlier, and nobody had ever clicked past it.

## Why there was no other way in

At [Doorvana](https://noconaconsulting.com/work/) the standard New Lead page cannot create a homeowner lead. `Lead.Company` is required, the household name is supposed to be derived rather than typed, and the platform refuses every layout workaround — the full story is in [the household model post](https://noconaconsulting.com/blog/household-accounts-without-person-accounts/). So lead creation goes through a screen flow, `New_Service_Lead`, and the New action on Lead is overridden to launch it.

An action override cannot point at a flow. `ActionOverrideType` has no Flow value, so the flow sits inside a minimal Aura wrapper that implements `lightning:actionOverride` and hosts `lightning:flow`:

force-app/main/default/aura/NewServiceLeadOverride/NewServiceLeadOverride.cmp

```xml
<aura:component implements="lightning:actionOverride,lightning:isUrlAddressable" access="global">
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:flow aura:id="serviceLeadFlow" onstatuschange="{!c.handleStatusChange}"/>
</aura:component>
```

The override is set for both the `Large` and `Small` form factors:

force-app/main/default/objects/Lead/Lead.object-meta.xml

```xml
<actionOverrides>
    <actionName>New</actionName>
    <content>NewServiceLeadOverride</content>
    <formFactor>Large</formFactor>
    <skipRecordTypeSelect>false</skipRecordTypeSelect>
    <type>LightningComponent</type>
</actionOverrides>
<actionOverrides>
    <actionName>New</actionName>
    <content>NewServiceLeadOverride</content>
    <formFactor>Small</formFactor>
    <skipRecordTypeSelect>false</skipRecordTypeSelect>
    <type>LightningComponent</type>
</actionOverrides>
```

That is the stakes. With New overridden on desktop and mobile, this flow is the only route by which a person can hand-key a Lead. A screen that cannot be left is not a cosmetic defect; it is the intake process stopping.

## allowFinish is the Next button

Here is the first screen as it was built:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml (before)

```xml
<screens>
    <name>Who_Is_This</name>
    <label>Who is this?</label>
    <allowBack>true</allowBack>
    <allowFinish>false</allowFinish>
    <allowPause>false</allowPause>
    <connector>
        <targetReference>Business_Name_Supplied</targetReference>
    </connector>
    ...
    <showFooter>true</showFooter>
    <showHeader>true</showHeader>
</screens>
```

Read for navigation, that XML looks fine. There is a `<connector>` to the next element. The footer is switched on. `allowFinish` false reads as “don’t let them finish the flow from here”, which is exactly right for screen one of four.

It is not what it means. **`allowFinish` controls the forward button, whatever it is labelled.** On a screen with an outgoing connector that button says Next; on the last screen it says Finish. Set `allowFinish` to false and the button goes, connector or no connector. In Flow Builder the same setting is the footer’s **Next or Finish** button, which is a much more honest name than the metadata’s.

Then add the first-screen rule: there is nothing to go back to, so `allowBack` renders nothing either. `showFooter` true with no buttons to show is a footer with nothing in it.

allowFinish false hides Next, not only Finish

In screen flow metadata, `allowFinish` decides whether the forward navigation button exists on that screen. On a mid-flow screen with a valid `<connector>`, `allowFinish` false still removes Next. If a screen should move forward, it needs `allowFinish` true.

Three screens had it false: `Who_Is_This`, `Need_Business_Name` and `What_Do_They_Need`. The fourth, `Where_Is_It`, had it true — which is why, in a flow nobody could get into, the one screen nobody reached was the one that would have worked. Every other screen flow in the project already set it correctly. The fix was three lines:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml (diff)

```diff
     <name>Who_Is_This</name>
     <label>Who is this?</label>
     <allowBack>true</allowBack>
-    <allowFinish>false</allowFinish>
+    <allowFinish>true</allowFinish>
     <allowPause>false</allowPause>
     <connector>
         <targetReference>Business_Name_Supplied</targetReference>
```

### Ruling out the obvious suspect

The org had recently moved to API 68, and “it worked before the release” is the first theory anyone reaches for. It was ruled out quickly, and the order of checks is worth stealing:

1.  The **active flow version in the org matched source**, so nothing had been edited in Setup behind the repo’s back.
2.  The **Aura wrapper was unchanged since the day it was built**.
3.  The flow’s own history showed `allowFinish` false on those screens **since that same day**.

So it had never worked. It had simply never been clicked. The build-log entries for that first week record deploys and Apex tests; none of them record anyone walking through the screens.

A deploy proves nothing about navigation

A screen flow with no way forward deploys cleanly, activates, and passes every Apex test that drives the records behind it. The only test that catches a missing button is a person clicking through every screen, on every branch, after every change to the screen elements.

## Fixing the button exposed the next bug

With Next back, the flow could finally reach its own decision logic — and the first branch anyone tried did the wrong thing.

The rule: a lead for anyone other than a homeowner is named from its business, so if the type is not Residential and Business Name is blank, the flow should stop on a warning screen straight away, rather than let the user fill in two more screens and hit a validation rule on save. The decision was written like this:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml (before)

```xml
<conditions>
    <leftValueReference>Business_Name</leftValueReference>
    <operator>IsNull</operator>
    <rightValue>
        <booleanValue>true</booleanValue>
    </rightValue>
</conditions>
```

In the browser, a Builder lead with a blank Business Name went straight past the warning to `What_Do_They_Need`. The `IsNull` test did not match an input the user had left empty.

The working explanation is that a blank screen input reaches the decision as an empty string, not null. That is inferred from the behaviour and from what fixed it — it was not isolated.

The test steps written alongside the fix said to expect the warning screen. The first browser run contradicted them a few minutes later. That is a small thing and also the whole lesson: the expectation was written before anyone had seen the flow run, which is the same gap that let the missing button live for six weeks.

### The fix that did not deploy

The first attempt compared the input to the empty-string global constant. The dry run refused it:

```plaintext
The "$GlobalConstant.EmptyString" element doesn't exist. Remove references to the element in all conditions.
```

What worked was taking the test out of the decision operator entirely and putting it in a Boolean formula resource:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml

```xml
<formulas>
    <description>A blank screen input does not satisfy IsNull in the decision, so blankness
      is tested here. TRIM also catches a name that is only spaces.</description>
    <name>Business_Name_Is_Blank</name>
    <dataType>Boolean</dataType>
    <expression>ISBLANK(TRIM({!Business_Name}))</expression>
</formulas>
```

The decision now tests `Business_Name_Is_Blank` `EqualTo` true. Both cases — empty and spaces-only — were confirmed in the browser.

Test screen input blankness with ISBLANK, not IsNull

For a text value that came from a screen input, use a Boolean formula with `ISBLANK(TRIM({!Input}))` and test the formula in the decision. `IsNull` true did not match a blank input here, and the `$GlobalConstant.EmptyString` comparison would not deploy.

One defect had been hiding the other by blocking the only route to it. That is worth expecting whenever a flow has been unreachable: fixing the entrance is the first test the rest of it has ever had.

## A save that failed with nowhere to go

The `Create_Lead` element had no fault path. Any save error — a validation rule, a malformed email — would end the interview on the platform’s generic flow error. It gained a `faultConnector` to a `Lead_Not_Saved` screen that shows `$Flow.FaultMessage` and leaves Previous available, so the user can correct entries instead of retyping them:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml

```xml
<faultConnector>
    <targetReference>Lead_Not_Saved</targetReference>
</faultConnector>
```

A deliberately malformed email then reached that screen with no Lead created, which proved the path. The raw message, though, was a paragraph of wrapper text around an `INVALID_EMAIL_ADDRESS` code, ending in a pointer to a SOAP API guide — accurate and useless to someone at a front desk.

Two formula resources now trim it. The first strips the sentence the platform puts before and after the real error; the second drops a leading exception code such as `INVALID_EMAIL_ADDRESS:`. Both fall back to the untouched message if the wording ever differs:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml

```xml
<formulas>
    <description>Removes the leading exception code, such as INVALID_EMAIL_ADDRESS, so the
      user reads only the explanation.</description>
    <name>Save_Error_Text</name>
    <dataType>String</dataType>
    <expression>IF(
  REGEX({!Save_Error_Core}, "[A-Z_]+: .*"),
  MID({!Save_Error_Core}, FIND(": ", {!Save_Error_Core}) + 2, LEN({!Save_Error_Core})),
  {!Save_Error_Core}
)</expression>
</formulas>
```

A 42-character First Name now reads `First Name: data value too large: ... (max length=40).` — still the platform’s wording, but without the paragraph around it.

The email case should not reach the save at all, so the `Email` screen field gained a `validationRule` that stops a malformed address on screen one:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml

```xml
<validationRule>
    <errorMessage>&lt;p&gt;Enter a valid email address, like name@example.com, or leave this blank.&lt;/p&gt;</errorMessage>
    <formulaExpression>OR(ISBLANK({!Email}), REGEX({!Email}, "[^@\\s]+@[^@\\s]+\\.[^@\\s]{2,}"))</formulaExpression>
</validationRule>
```

It checks the shape of the address and nothing more. A typo in a real-looking domain still passes, and nothing short of sending mail will catch that.

## Going back is not the same as looping back

The Business Name warning screen originally said “Next returns you to the first screen”, and it did: `Need_Business_Name` had a `<connector>` pointing back at `Who_Is_This`.

Following it forward produced the first screen, blank. Every name, email and phone number the user had typed was gone. Pressing **Previous** from the same warning screen produced the same first screen with every value intact. Previous restored entered values on every screen tested; the connector to the same screen did not.

A connector back to an earlier screen is not Previous

In this flow, looping forward along a connector to an earlier screen showed it empty, while Previous kept the entries. If the intent is “go back and fix it”, offer Previous and remove the loop.

The fix used the same setting that caused the first bug, this time on purpose. The connector was removed and the warning screen set to `allowFinish` false, so Previous is the only button on it:

force-app/main/default/flows/New\_Service\_Lead.flow-meta.xml (diff)

```diff
     <allowBack>true</allowBack>
-    <allowFinish>true</allowFinish>
+    <allowFinish>false</allowFinish>
     <allowPause>false</allowPause>
-    <connector>
-        <targetReference>Who_Is_This</targetReference>
-    </connector>
```

The warning text changed to match: _Click Previous to enter a Business Name — the lead cannot be saved without one. Your entries are kept._

## What was verified, and what was not

Every fix was deployed to the sandbox and clicked through in the browser. A blank email, a homeowner lead whose Company was derived as `{First} {Last} Household` by the before-save flow `Service_Lead_Stamp_Company`, and the Builder path were each confirmed by saving fabricated Leads, reading one back, and deleting them. Lead conversion was not part of these runs.

## Practical summary

-   `allowFinish` on a screen controls the forward button — Next on a mid-flow screen, Finish on the last. `allowFinish` false with a valid `<connector>` still leaves no way forward.
-   On a flow’s first screen there is no Previous either, so `allowFinish` false there renders an empty footer.
-   An `ActionOverrideType` cannot be Flow. Override New with an Aura component that implements `lightning:actionOverride` and hosts `lightning:flow` — and once you have, that flow is the only way in, so treat its navigation as critical path.
-   `IsNull` true did not match a blank screen input. Test `ISBLANK(TRIM({!Input}))` in a Boolean formula resource instead; `$GlobalConstant.EmptyString` in a condition would not deploy.
-   Give every Create Records element in a screen flow a `faultConnector`, and show a trimmed `$Flow.FaultMessage` on a screen that keeps Previous available.
-   Previous keeps entered values; a connector looping back to the same screen did not.
-   A deploy, an activation and a green Apex run say nothing about whether a screen can be left. Click through every screen on every branch.

-   Flow
-   Screen flows
-   Lead
-   Aura
-   Action overrides
-   Testing

Disclosure: Doorvana's owner is also a co-owner of Nocona Consulting. This is a real engagement between two separate companies, but not an arm's-length one — and not an independent reference. [More on the work page](https://noconaconsulting.com/work/).

## FAQ

### Why is the Next button missing from a Salesforce screen flow?

Check allowFinish on the screen. Despite the name, in screen flow metadata allowFinish controls the forward navigation button, whichever label it carries: on a screen with an outgoing connector that button is Next, and on the last screen it is Finish. With allowFinish set to false the button is hidden even though the screen has a valid connector and showFooter is true. On the first screen of a flow there is no Previous button either, so the footer renders with nothing in it.

### Does IsNull match a blank text input in a Salesforce flow decision?

Not reliably. In this build a decision testing a screen text input with the IsNull operator set to true did not match when the user left the field blank, so the branch for a missing value never ran. A Boolean formula resource using ISBLANK(TRIM({!Field})) did match, and also catches a value of only spaces. That a blank screen input arrives as an empty string rather than null is inferred from the behaviour, not documented.

### What does The $GlobalConstant.EmptyString element doesn't exist mean in a flow deploy?

It is the error a deploy or dry run returned when a flow decision condition referenced $GlobalConstant.EmptyString as an element reference in metadata. The deploy refused it with: The "$GlobalConstant.EmptyString" element doesn't exist. Remove references to the element in all conditions. Testing blankness with a Boolean formula resource such as ISBLANK(TRIM({!Field})) avoids the global constant entirely.

### Does a flow connector back to an earlier screen keep the values the user entered?

In this build it did not. Following a connector forward to an earlier screen showed that screen with its inputs empty, while the Previous button on the same screens restored every entered value. To send a user back to correct something, offer Previous rather than a connector that loops back.

### Can a Salesforce flow override the standard New button on an object?

Not directly. An action override's type can be a Lightning component, a Visualforce page or the default, but there is no Flow value. The usual pattern is a small Aura component that implements lightning:actionOverride and hosts the flow with lightning:flow, then point the New override at that component for the Large and Small form factors.
