Troubleshooting
Common issues and their solutions when working with Forma.
Expression Errors
"Expression evaluation failed"
Symptoms: Field shows unexpected behavior, computed value is empty, or console shows FEEL error.
Common Causes:
-
Invalid FEEL syntax
// Wrong - using == instead of =
{ "visibleWhen": "status == \"active\"" }
// Correct
{ "visibleWhen": "status = \"active\"" } -
Undefined variable reference
// Wrong - typo in field name
{ "visibleWhen": "usrName != null" }
// Correct
{ "visibleWhen": "userName != null" } -
Missing quotes around strings
// Wrong - missing escaped quotes
{ "visibleWhen": "country = US" }
// Correct
{ "visibleWhen": "country = \"US\"" }
Solution: Check the expression syntax and ensure all field names match exactly.
Computed field shows undefined
Symptoms: Computed field displays nothing or shows undefined.
Cause: The expression references a field that has no value yet (null).
Solution: Add null checks to your expression:
// Before
{
"expression": "quantity * unitPrice"
}
// After - with null handling
{
"expression": "if quantity != null and unitPrice != null then quantity * unitPrice else 0"
}
Expression returns wrong type
Symptoms: Boolean expression doesn't work as expected.
Cause: Comparing values of different types.
// Wrong - comparing number to string
{ "visibleWhen": "quantity = \"5\"" }
// Correct - comparing number to number
{ "visibleWhen": "quantity = 5" }
Solution: Ensure you're comparing values of the same type.
Visibility Issues
Field not showing despite condition being true
Check these in order:
-
Field is in
fieldOrder{
"fields": {
"conditionalField": { "label": "...", "visibleWhen": "..." }
},
"fieldOrder": ["otherField", "conditionalField"] // Must be listed
} -
Parent page is visible (for multi-page forms)
{
"pages": [
{
"id": "details",
"visibleWhen": "showDetails = true", // Parent must also be visible
"fields": ["conditionalField"]
}
]
} -
No typos in condition
// Check exact field name spelling
{ "visibleWhen": "hasInsurance = true" } // Is it "hasInsurance" or "has_insurance"?
Field flickers or rapidly shows/hides
Cause: Expression depends on a value that changes frequently.
Solution:
- Debounce your validation:
validationDebounceMs: 300 - Check if the expression creates a circular dependency
Validation Issues
Validation not running
Check:
-
validateOnsetting// Validation only runs on submit
useForma({ spec, validateOn: "submit" });
// Validation runs on blur (default)
useForma({ spec, validateOn: "blur" });
// Validation runs on every change
useForma({ spec, validateOn: "change" }); -
Field is visible - Hidden fields skip validation
-
Schema is correct - Type constraints come from JSON Schema
Custom validation not triggering
Cause: Schema validation must pass first.
{
"schema": {
"properties": {
"email": { "type": "string" } // Schema validation runs first
}
},
"fields": {
"email": {
"validations": [
// Custom rules run only after schema passes
{ "rule": "contains(value, \"@company.com\")", "message": "..." }
]
}
}
}
Required field not showing error
Check:
-
Field is in schema's
requiredarray or hasrequiredWhen{
"schema": {
"required": ["email", "name"]
}
} -
Field is visible - Hidden required fields don't error
-
requiredWhenexpression is correct{ "requiredWhen": "needsShipping = true" }
Array Field Issues
Can't add more items
Check maxItems constraint:
{
"schema": {
"properties": {
"items": {
"type": "array",
"maxItems": 5 // Limit reached?
}
}
}
}
Check canAdd before rendering button:
<button disabled={!helpers.canAdd}>Add Item</button>
Can't remove items
Check minItems constraint:
{
"schema": {
"properties": {
"items": {
"type": "array",
"minItems": 1 // Must have at least 1
}
}
}
}
Array item values not updating
Ensure correct path format:
// Correct path format
forma.setFieldValue(`items[${index}].name`, newValue);
// Not
forma.setFieldValue(`items.${index}.name`, newValue); // Wrong
Computed Field Issues
Computed value not updating
Check order of computed fields:
{
"computed": {
"subtotal": { "expression": "quantity * price" },
"tax": { "expression": "computed.subtotal * 0.1" }, // Must come after subtotal
"total": { "expression": "computed.subtotal + computed.tax" } // Must come last
}
}
Note: Computed fields are evaluated in order. A field can only reference computed fields defined before it.
Computed field shows NaN
Cause: Arithmetic operation with null or non-numeric value.
Solution:
{
"expression": "if quantity != null and price != null then quantity * price else 0"
}
Format not applying
Ensure display: true is set:
{
"total": {
"expression": "subtotal + tax",
"format": "currency",
"display": true // Required for format to show
}
}
Reference Data Issues
Lookup returns null
Check:
-
Key exists in reference data
{
"referenceData": {
"rates": { "CA": 0.0725, "NY": 0.08 } // "TX" doesn't exist
}
} -
Use
get value()for dynamic keys// Dynamic lookup (field value as key)
{ "expression": "get value(ref.rates, state)" }
// Static lookup (fixed key)
{ "expression": "ref.rates.CA" } -
Handle missing keys
{
"expression": "if get value(ref.rates, state) != null then get value(ref.rates, state) else 0"
}
Wizard Issues
Page navigation not working
Check:
-
Current page validation -
nextPage()validates before proceeding// This validates current page first
wizard.nextPage();
// Check if validation passes
console.log(wizard.canProceed); -
Conditional pages - Page might be hidden
{
"pages": [
{ "id": "step1", "fields": [...] },
{ "id": "step2", "visibleWhen": "step1Complete = true", "fields": [...] }
]
}
Progress percentage incorrect
Cause: Hidden pages are excluded from count.
This is expected behavior. The wizard recalculates progress based on visible pages only.
Performance Issues
Form is slow with many fields
Solutions:
-
Use
validationDebounceMsuseForma({ spec, validationDebounceMs: 300 }); -
Simplify complex expressions - Combine multiple simple conditions
-
Reduce reference data size - Large lookup tables impact performance
Re-renders on every keystroke
Use appropriate validateOn:
// Validate on blur instead of change
useForma({ spec, validateOn: "blur" });
Debugging Tips
Log form state
const forma = useForma({ spec });
// Log on changes
useEffect(() => {
console.log("Data:", forma.data);
console.log("Computed:", forma.computed);
console.log("Errors:", forma.errors);
console.log("Visibility:", forma.visibility);
}, [forma.data]);
Test expressions in isolation
import { evaluate } from "@fogpipe/forma-core";
const result = evaluate("age >= 18", { data: { age: 21 } });
console.log(result);
// { success: true, value: true }
Validate specification
import { validateSpecification } from "@fogpipe/forma-core";
const errors = validateSpecification(spec);
if (errors.length > 0) {
console.error("Spec errors:", errors);
}