Troubleshooting
Most common deployment and runtime issues and how to diagnose them.
Debug Mode and Console
Debug mode prints to the browser console (F12, Console tab) why rules behave the way they do. It is not just for designers: an administrator can see whether a script ran, whether a rule was skipped due to invalid fields, and what marked a field as "dirty".
Enabling Debug Mode
| Method | Scope |
|---|---|
URL query parameter ?fcdebug=1 (also accepts true, yes, on) | For this page load only. Nothing is saved. |
In console: localStorage.setItem('fc.debug', '1') and reload the page | Persistent in this browser until you remove the key. |
Form Settings, toggle "Debug mode for rules and scripts" (debugMode) | For all form users, saved in the configuration. See Debug Mode. |
Debug mode is evaluated when the form opens. When disabled, nothing is logged or allocated. Log entries are prefixed with [FC debug].
What Is Logged
- Rule evaluation (collapsed group
rules …with reason, form mode, and count of matched rules). Inside, each rule showsMATCH/no matchwith a condition table (field, operator, expected and actual value, result) and a table of executed actions. Skipped rules have aSKIPPEDline with the reason: disabled (disabled), invalid (invalidReason), trigger mismatch (trigger), or no conditions. - Lifecycle (
lifecycle onLoadandonSave): field changes, called scripts, errors blocking save. - Forced values (
forcedValue): field change from a rule, orBLOCKED by loop guardwhen rules overwrite a field in a loop (protection after 10 applications per second). - Scripts (
script <source> - ok / ERROR, duration, result, messages, error) andscript skipped: tenant policy disabledwhen the script policy is disabled. - Expressions:
expression parse error(expression was used as a text template) andexpression non-finite result(division by zero or NaN; target field is cleared). - Dirty state changes (
dirtyFields changed): table of fields that became dirty and the source of the change (script:onFormLoad,rule:forcedValue, user/widget…). Useful for diagnosing a form that reports unsaved changes immediately upon opening.
Render Counter
In debug mode, window.__fcRenderCounts is available: the render count of individual components (by field name). Type it into the console to check whether a single field is causing the whole form to re-render. In normal operation, it has zero overhead.
// after enabling debug mode and opening the form
console.table(window.__fcRenderCounts)
Form Does Not Appear
- Is the form active? Run
Manage-FormCustomizer.ps1 -Action Statusor open the "Custom form" dialog (if the form is already active, the command bar button is named "Open FormCraft 365 editor" and activation status is in the designer under "List Activation"). See Activation. Status "OTHER COMPONENT" means the list uses a different form. - Is the package deployed and enabled? In the App Catalog, verify that the "Enabled" and "Deployed" columns are set and that tenant-wide deployment was selected.
- Upgrade did not take effect: after uploading a new version, hard-refresh the page (Ctrl+F5). The new version must have a higher version number (see Upgrading).
- Form opens with the default layout: the configuration failed to load. See Configuration Load States.
- Open the console and look for an error prefixed with
[CustomFormCustomizer]or the message "Error initializing form".
Configuration Load States
When opening the form, configuration is read from the list's config.json and backup.json files and evaluated into one of four states.
| State | Meaning | Behavior |
|---|---|---|
ok | Valid configuration found (or migrated from an older schema version). | Form runs according to the configuration. |
notFound | File does not exist (HTTP 404). No one has saved the form yet. | Default layout from list columns is used. Saving works normally. |
invalid | File exists, but contains broken JSON or does not match the schema (and no newer valid copy exists). | Form runs with the default layout, nothing is overwritten, saving is blocked. Admin sees a "Fix configuration" banner (see Raw JSON). |
unreadable | Reading failed for a reason other than 404 (403, 429, 5xx, network). | Default layout, saving blocked ("Failed to read saved configuration"). Regular users see "The form could not be loaded completely. Please contact the site owner." Refresh the page and verify read permissions on the FormCustomizer folder (see Permissions). |
The ok state can also carry a "newer version" flag; see below.
Invalid Configuration and the Raw JSON Panel
If the saved configuration is invalid, it is never silently overwritten with the default state. The form administrator receives a warning and a Fix configuration button, which opens the designer with the Saved configuration is invalid panel.
- In the panel, review Issues found (schema path and reason, or JSON syntax error).
- Edit the JSON in the Saved configuration (Raw JSON) field. Typically, you add a missing required property or fix a typo in a field type name.
- Click Validate and apply JSON. A valid configuration loads into the designer and saving is unlocked.
- Save your changes using the normal save button.
Unknown keys from the saved JSON are preserved during repair. If you cannot fix the error, use a file from history or "Restore from backup" in the designer menu (the last valid backup backup.json).
Configuration History
Before every overwrite, the previous configuration is copied to SiteAssets/FormCustomizer/<listId>/history/ as <listId>.<timestamp>.json. The last 10 versions are kept. Writing history has a 5-second timeout and its failure does not block saving. On the first storage lock, pre-lock history is deleted (untrusted content).
The designer does not yet have a UI button to restore from history. Procedure:
- Open the Site Assets library, folder
FormCustomizer/<listId>/history(you can find the list ID in the list settings URL or viaGet-PnPList). - Download the desired version and open it in a text editor.
- In the designer, open the Raw JSON panel, paste the contents, and click Apply JSON, or use configuration import.
- Save the form.
The most recent backup (one version) is also available in the designer menu as Restore from backup.
Configuration from a Newer Product Version
Every saved configuration carries a schemaVersion. If it is higher than the version supported by the package (for example, you uploaded an older .sppkg), the form renders on a "best-effort" basis, but saving is blocked to prevent data loss. The designer displays "Configuration comes from a newer product version" with the schema versions. Resolution: upgrade the package to the newer version (see Upgrading). Do not overwrite the configuration with an older version.
Configuration Does Not Save or Is Lost
HTTP 403 When Saving
The message "You do not have permission to perform this operation in SharePoint (HTTP 403)" means the user lacks write access to the configuration folder. Most common causes:
- Storage is locked and the user is neither a site owner nor a member of the designer group (with a list subfolder configured for it). Add them to the designer group and have a site owner save the form again (see Designer Group).
- A designer is saving to a list whose folder has not been created yet: "This list's configuration folder does not exist yet. A site owner must save the form first."
- Saving a license into a locked folder as a member: "Only site owners can save the license into the locked FormCustomizer folder."
- Saving to a tenant Storage Entity (license, script policy) requires a tenant App Catalog administrator.
Storage Is Not Locked
The warning "Configuration storage is not locked: anyone with Manage Lists permission can overwrite it" is shown to a site owner after saving if locking failed or has not been set up. Resolution: save the form (or click Lock Now) as a site owner with Manage Permissions, or run the command from PowerShell. Message variants:
- Storage locking failed (…): try again as an owner or run PowerShell.
- Failed to restore original permissions: the folder may have restricted access; run the PowerShell repair.
- Failed to set read access for: …: the lock is active, but the organization or guest principal could not be resolved (e.g., tenant restriction). Disable the corresponding toggle.
- Designer group … does not exist / is Members or Visitors group / contains Everyone: fix the group name (see Rejected Groups).
HTTP 400 Error on File Paths
The message "Specified value is not supported for the serverRelativePath parameter" (HTTP 400) means a web-relative path was sent to SharePoint. File and folder functions require a server-relative path (/sites/<site>/SiteAssets/…). The product constructs paths properly. You will mainly encounter this in custom scripts, queries, or manual code edits: use toServerRelativePath.
Save Conflict (412)
When saving an item, its ETag is checked: if another user modified it in the meantime, SharePoint returns HTTP 412 and the form shows the Item was modified elsewhere dialog with details on who changed it and when. The user chooses:
- Reload: discards their changes and loads the current version,
- Overwrite anyway: saves their values over the other user's changes,
- Cancel: returns to the form.
This is not a deployment bug. If you see unusually many conflicts, look for a workflow or automation modifying the item shortly after the form is opened. The message "The item was modified by another user in the meantime. Please refresh the page (HTTP 412)" appears for operations that do not offer the dialog. This behavior is described in Working with the Form. Form configuration does not report 412 conflicts (it saves based on savedAt, not ETag).
Unloaded Fields
Item values are loaded in batches ($select / $expand). If a batch fails (source list permissions, SharePoint error), the form still opens and displays fields from the failed batch as read-only with a banner "Fields failed to load and are read-only (will not be saved): …". On save, they are not written, preventing data from being overwritten with empty values. Resolution: reload the form, verify the user has read access to source lists (lookup, taxonomy, people).
Unindexed Column
On lists with more than 5,000 items, SharePoint rejects queries filtering on an unindexed column (list view threshold). Related Items and Related Documents widgets therefore do not run such a query and display "Column "…" is not indexed. On lists with more than 5,000 items, it must be indexed." Resolution:
- In the source list, create an index on the foreign key column (List Settings, Indexed columns), or
- in the designer under the widget's data source, click Index column (requires Manage Lists permission).
Search in lookup fields over 500 items automatically switches to querying after typing at least two characters (showing the hint "Start typing to search…"), so indexing does not need to be handled there.
Scripts Are Not Working
- Are scripts enabled? The default state is disabled. Form administrators will see a banner "Custom scripts are disabled on this tenant…". To enable, see Script Policy. Changes take up to 15 minutes to take effect.
- In debug mode, look for
script skipped: tenant policy disabled(policy) orscript … ERROR(code error). - A message about CSP /
unsafe-evalmeans the environment prohibits dynamic execution; see CSP. - When scripts are disabled,
onBeforeSavedoes not run and saving is not blocked. Use rules with theblockSaveaction.
License Was Not Recognized
The designer shows Community Free even though you have a key:
- Open the License dialog and paste the key again. The dialog validates it and explains the reason (different tenant, different site collection, expired, invalid signature…). The error table is in Licensing.
- Verify the key is stored where it is read: tenant Storage Entity, or
SiteAssets/FormCustomizer/license.txtin the root web of the site collection. - A change made outside the designer (PowerShell, manual file) may take up to an hour to appear (raw key cache). It takes effect immediately after clearing
_fc_lic_*keys inlocalStorage. - A key for specific site collections does not apply to others. Send the vendor the Site Collection ID from the dialog.
"Custom form" Button Missing from List Command Bar
Work through these steps in order. The first steps reveal the most common causes:
- Check the … overflow menu at the right end of the command bar. If the bar is crowded, SharePoint moves custom commands there. The extension cannot control this.
- Microsoft Lists sync. Symptom: the first load after "Clear site data" shows the button, subsequent refreshes (F5) do not; other lists not handled by sync work fine. The cause is the local OneDrive sync client (Microsoft Nucleus), which serves list data locally via a service worker. Its response has
"ShouldLoadSPFramework": falseand custom actions without SPFx extensions, so SharePoint only preloads the extension package ("preloaded but not used") and the command set'sonInitis never called. Our code cannot influence this; SPFx does not run at all. Verification: F12, Network tab, theRenderListDataAsStreamrequest goes tolocalhost:42050(or has headerserver: MicrosoftNucleus). Recommended permanent fix: in List Settings (Advanced settings, Offline Client Availability) choose No, or leave Disable offline availability of the list checked when activating the form (sets theExcludeFromOfflineClientlist property; the list will not be available offline). The designer warns about this on the List Actions tab. Tenant or device-level alternative: theDisableListSyncpolicy. Other options: open the list in a way not served by Lists sync, or temporarily clear site data; permanently, the tenant or user can disable Microsoft Lists sync (check Microsoft documentation for options; verifySet-SPOTenant -DisableListSyncin Microsoft documentation). - In the Tenant Wide Extensions list, no Form Customizer component entry may have Disabled = Yes. SharePoint does not deliver disabled entries at all, so the corresponding command (e.g.,
FormActivatorCommandSet-100for the command bar) will not run. - Only users with the
ManageWebpermission on the list (site owners, Full Control) see the button. The check result is cached insessionStorageper tab, so open the list in a new tab, especially after permission changes. - Try opening the list in an incognito/private window. If the button appears there, the regular window is holding stale site data (typically after fixing Tenant Wide Extensions entries): F12, Application tab, Storage, Clear site data, then Ctrl+F5.
- The command is available on lists with template 100, 120, and 1100. Document libraries (template 101) do not have the command.
- In the App Catalog, check the Tenant Wide Extensions list. It must contain 6 entries for templates 100, 120, and 1100: 3 command bar entries with Component Id
4a8b7c12-5d3e-4f9a-8b1c-6e2d9f4a3b5cand 3 context menu entries with Component Ida9998067-8e06-423f-b8a0-3177988f3a42(since version 1.28.1). Delete old context menu entries (FormActivatorCommandSet-ContextMenu-*), as they create duplicate registrations. Add missing ones and delete obsolete ones; see Installation. - Verify the package loaded. In the browser console (F12), run
performance.getEntriesByType("resource").some(e => e.name.includes("form-activator")).truemeans the extension loaded. After navigating between lists in the app, the value may belong to a previous list, so check in a new tab with the list open. - Changes take effect on sites within approximately 20 minutes. Afterwards, refresh the page with Ctrl+F5.
- Enable extension diagnostics. In the browser console (F12) on the list page, run
localStorage.setItem("fc.debug","1")and refresh the page. Logs appear as console warnings (console.warn) prefixed with[FormCraft]. SharePoint clears the console during load, so enable Preserve log in DevTools console settings. Lines starting with[FormCraft]show which component is running (FormActivatorCommandSet = command bar, FormListActionsContextMenu = context menu), its registration properties, list ID and template, permission check inputs and resulting main command visibility, count of loaded list actions, visibility decisions for individual slots, and every command bar redraw. If no[FormCraft]line appears, the component did not start (see Microsoft Lists sync and registration check above). Disable diagnostics withlocalStorage.removeItem("fc.debug").
Console Noise
Some console messages are not errors:
- HTTP 404 requests for
config.json,backup.json,license.txt,history, or Storage Entity: the file does not exist yet (the form has never been saved, or no key is set). This is expected and does not affect functionality. [ConfigService] …warnings: auxiliary operations that can fail without affecting the save (copying to history, history cleanup, verifying designer group members).- Messages from SharePoint's own code and other page parts (SPFx host, web parts, telemetry) are unrelated to this product.
You can recognize a real issue by a UI banner (red or yellow bar) or an error prefixed with [CustomFormCustomizer], [FormActivatorCommandSet], or [FC debug] (in debug mode only).
What to Send to Support
Prepare the following details (without personal data):
- Package version (
solution.versionfrom the App Catalog) and documentation version. - Site URL and list ID, form mode (new, edit, display), and steps to reproduce.
- Output of
Manage-FormCustomizer.ps1 -Action Status. - Browser console output from a load with
?fcdebug=1enabled (save as text; verify it contains no form data). - Network tab showing failed requests (status, URL, response body).
- Form configuration: export from the designer (Export button), or
config.jsonfrom the list folder. - Configuration storage state (locked, unlocked, designer group) and whether the script policy is enabled.
- For licensing: Tenant ID and Site Collection ID from the dialog and the exact error message (do not send the key itself over an insecure channel).