From Zenith's built-in Creator knowledge pack, version 1.0.0 (2026-10-10). Rule ids are stable, so you can refer to them in your project rules, code reviews and tickets.
Syntax 9
Syntax error
The code does not parse: unbalanced brackets, an unterminated string or comment, or a token Deluge can't accept here. When Zenith's parser is only unsure (a construct it does not know), the finding is a warning; Creator's compiler has the final say.
Example
Works
if(x > 1)
{
info x;
}
No comments inside insert/update blocks or multi-line call arguments
Comments inside insert into X [ … ] or update … [ … ] blocks, or between the arguments of a multi-line call, have caused 'Improper Statement' save errors. Put comments before the statement.
Example
Fails
new_id = insert into Orders
[
Customer = customer_id_param
// default status
Status = "Open"
];
Works
// default status is Open
new_id = insert into Orders
[
Customer = customer_id_param
Status = "Open"
];
Smart quotes and look-alike punctuation
Curly quotes (“ ” ‘ ’), full-width semicolons and similar characters pasted from documents break parsing outside string literals.
Example
Fails
status_value = “Open”;
Works
status_value = "Open";
Missing semicolon
Every statement ends with ; (Creator: 'Improper Statement Error might be due to missing ';' …'). Creator often reports the line after the one that is missing it.
Example
Fails
total = 0
info total;
Works
total = 0;
info total;
Zoho docs: Deluge error messages
No ?: ternary: use if(cond, a, b)
Deluge has no ternary operator. The conditional if(condition, a, b) function returns one of two values.
Example
Fails
label = order_total > 1000 ? "Large" : "Standard";
Works
label = if(order_total > 1000, "Large", "Standard");
Zoho docs: Conditional statements
No ++ / --: use += 1 or x = x + 1
Deluge has no increment or decrement operators. Compound assignment (+=, -=, *=, /=, %=) is supported.
Example
Zoho docs: Assignment operators
String literal ending in a backslash
A string whose last character is \ escapes its own closing quote, which Creator reports as Improper Statement. Don't end a literal with a backslash; to end text with one, build it with "5c".hexToText() and concatenate. Inside a literal, Zoho's regex examples write one backslash as \\.
Example
Fails
separator_text = "\";
Works
backslash_char = "5c".hexToText();
windows_path = "C:" + backslash_char + "exports" + backslash_char;
Zoho docs: Deluge error messages
JavaScript/Python-style APIs that don't exist in Deluge
APIs that look right but don't exist in Deluge: .forEach, .map, .filter, .push, .append(…), .length without parentheses, JSON.parse/JSON.stringify, console.log, print(), pow(), Math.*, str(), len(x) on lists. Use for each, .add(), .size(), toMap()/toString(), info, power(), and .length() on text.
Example
Fails
items.push(order_id);
payload = JSON.stringify(order_map);
Works
items.add(order_id);
payload = order_map.toString();
Zoho docs: Built-in functions
No namespace blocks, lambdas or nested function definitions
Functions are created one per editor entry (Namespace.Name in the signature). namespace X { … }, function(…) { … } lambdas and functions declared inside functions don't exist.
Example
Fails
namespace Orders
{
void Close(int order_id_param)
{
info order_id_param;
}
}
Works
void Orders.Close(int order_id_param)
{
info order_id_param;
}
Control flow 6
No while / do-while loops
Deluge has no while or do-while statement. Replace it with a bounded for each over a slot list (or a literal list) and break when done.
Example
Fails
while(has_more)
{
page = page + 1;
}
Works
slots = leftpad("1", 50).replaceAll(" ", "1,").toList(",");
has_more = true;
for each index page_index in slots
{
if(!has_more)
{
break;
}
has_more = false;
}
Zoho docs: for each element
No C-style or range-style for loops
for (i = 0; …), for i in range(n) and for i in 0..n do not exist. Use for each over a list, or for each index over a list for positions.
Example
Fails
for (i = 0; i < items.size(); i = i + 1)
{
info items.get(i);
}
Works
for each index i in items
{
info items.get(i);
}
Zoho docs: for each element
No sleep()/wait(): schedule instead
Deluge has no sleep, wait or delay function. Spread work over time with a Run_At date-time on a queue record (form schedule) or the next scheduled run.
Example
Fails
for each order_rec in batch_orders
{
thisapp.Orders.Push_To_Fulfillment(order_rec.ID);
sleep(500);
}
Works
offset_seconds = 0;
for each order_rec in batch_orders
{
offset_seconds += 10;
order_rec.Push_At = zoho.currenttime.addSeconds(60 + offset_seconds);
}
Zoho docs: Built-in functions
No switch/case: use if / else if
Deluge has no switch statement; chain if / else if / else, or map a key to a value with a Map.
Example
Fails
switch(status_value)
{
case "Open":
label = "Active";
}
Works
label_by_status = {"Open":"Active","Closed":"Done"};
label = ifnull(label_by_status.get(status_value), "Other");
Zoho docs: Conditional statements
for each index yields positions, not values
for each index i in L sets i to 0…L.size()-1. Iterating a computed range (for example a Range(5, 10) helper) with for each index processes positions 0…4, not 5…9. Use for each v in L for values; use index only with L.get(i).
Example
Fails
for each index i in thisapp.Util.Range(5, 10)
{
info items.get(i);
}
Works
for each i in thisapp.Util.Range(5, 10)
{
info items.get(i);
}
Zoho docs: for each index
Mixed && and || without parentheses in a condition (Creator: OR binds tighter)
Creator's documented logical precedence is NOT > OR > AND (other Zoho services and most languages put AND before OR), so if(a && b || c) means a && (b || c) in Creator. Parenthesize every group where && and || meet at the same level of an if, else if or conditional if(). There is no automatic fix: only the author knows the grouping they meant.
Example
Fails
if(order_status == "Open" && order_total > 1000 || is_priority == true)
{
info "review";
}
Works
if((order_status == "Open" && order_total > 1000) || is_priority == true)
{
info "review";
}
Zoho docs: Logical operators, Criteria in conditions
Functions 9
Typed function needs a return after try/catch / if-chains
A function with a non-void return type must end with a return statement reachable on every path; returns inside try and catch are not enough (Creator: 'Missing return statement: Provide <TYPE> expression to return').
Example
Fails
int Orders.Count_Open(int customer_id_param)
{
try
{
return Orders[Customer == customer_id_param].count();
}
catch (e)
{
return -1;
}
}
Works
int Orders.Count_Open(int customer_id_param)
{
try
{
return Orders[Customer == customer_id_param].count();
}
catch (e)
{
info e.message;
}
return -1;
}
Zoho docs: Deluge error messages
No default or optional parameters
Function parameters can't have default values and functions can't be overloaded; every call must pass exactly the declared arguments.
Example
Fails
map Orders.Search(string status_param = "Open", int limit_param = 50)
{
return Map();
}
Works
map Orders.Search(string status_param, int limit_param)
{
result = Map();
result.put("count", Orders[Status == status_param].count());
return result;
}
Zoho docs: Deluge error messages
Signature must be line 1 of a function file
Nothing (comments, blank lines, export headers) may come before <type> Namespace.Name(...). Put docs inside the body.
Example
Fails
// Function: Orders.Close
// Exported: 2026-01-01
void Orders.Close(int order_id_param)
{
info order_id_param;
}
Works
void Orders.Close(int order_id_param)
{
// Closes one order. Params: order_id_param = Orders.ID
info order_id_param;
}
No datetime type in signatures
datetime is not a Deluge type (Creator: 'Form 'datetime' does not exist'). Use date for date and date-time parameters and return types.
Example
Fails
string Tasks.Describe(datetime due_at_param)
{
return due_at_param.toString("dd-MMM-yyyy HH:mm");
}
Works
string Tasks.Describe(date due_at_param)
{
return due_at_param.toString("dd-MMM-yyyy HH:mm");
}
DLG104 Error Checks your app's schema Call argument count must match the signature
There are no optional parameters: thisapp.NS.Fn(...) must pass exactly the declared number of arguments. On code Creator already saved (the mirror) it is reported as a warning: the caller saved against an older signature (Creator does not re-check callers) and fails when it runs or is saved again.
Example
Fails
summary = thisapp.Invoices.Build_Summary(invoice_id);
Works
summary = thisapp.Invoices.Build_Summary(invoice_id, false);
Zoho docs: Deluge error messages
DLG105 Error Checks your app's schema Called function doesn't exist (yet)
Calling a function that doesn't exist fails to save (Creator: 'Not able to find … function'). It must exist in the app or be created earlier in the same deploy.
Example
Fails
thisapp.Orders.Recalc_Totals(order_id_param);
Works
thisapp.Orders.Recalculate_Totals(order_id_param);
Zoho docs: Deluge error messages
DLG106 Error Checks your app's schema Signature change without updating every caller
Changing the parameters of an existing function breaks every caller (functions, workflows, schedules, custom actions, report and lookup filters, pages). Update all callers in the same change and push the callee first.
Example
Fails
// feature changes Invoices.Build_Summary(int) to (int, bool) but leaves this caller:
summary = thisapp.Invoices.Build_Summary(invoice_id);
Works
summary = thisapp.Invoices.Build_Summary(invoice_id, false);
DLG114 Warning Checks your app's schema Result of a value-returning call is ignored
Creator saves bare calls of value-returning app functions (hundreds of them in production code), so those are only an info hint. A bare call of a pure built-in (text.trim();, ifnull(a, b);) does nothing and is a warning.
Example
Fails
thisapp.Invoices.Build_Summary(invoice_id, false);
Works
summary = thisapp.Invoices.Build_Summary(invoice_id, false);
Zoho docs: Deluge error messages
DLG115 Error Checks your app's schema Void function assigned or used in an expression
Assigning the result of a void function fails to save (Creator: '… cant be assigned to variable or used in expression'). On code Creator already saved (the mirror) it is reported as a warning: the caller saved before the callee became void and fails when it runs or is saved again.
Example
Fails
result = thisapp.Orders.Close(order_id_param);
Works
thisapp.Orders.Close(order_id_param);
Zoho docs: Deluge error messages
Criteria 9
Don't mix && and || in one fetch criteria
Creator's documented precedence is NOT > OR > AND (other Zoho apps differ), and parentheses have been seen not to apply inside Form[...] criteria. Same-field ORs: use in {}; cross-field ORs: separate fetches, or filter in code. Mixed criteria save and run in Creator; this flags a precedence hazard, not a save error.
Example
Fails
open_orders = Orders[Customer == customer_id_param && (Status == "Open" || Status == "On Hold")];
Works
open_orders = Orders[Customer == customer_id_param && Status in {"Open","On Hold"}];
Zoho docs: Logical operators
No .limit() / .maxRecords() / limit-offset: use range
Limit fetched rows with range from a to b (inclusive; 0 and 1 both mean the first record), after any sort by.
Example
Fails
stale_runs = Runs[Status == "Active"].limit(50);
Works
stale_runs = Runs[Status == "Active"] sort by ID range from 1 to 50;
Zoho docs: Fetch records
null can't be an element of in {}
Fetch without the null alternative and filter in code, or run a second fetch with Field == null.
Example
Fails
orders = Orders[Status in {"Open", null}];
Works
open_orders = Orders[Status == "Open"];
unset_orders = Orders[Status == null];
List literal with more than six elements in criteria
Zoho documents that LIST expressions in criteria cannot hold more than six elements. Keep literal in {…} sets to six or fewer, or move the values to a variable or lookup and test it in a sandbox.
Example
Fails
orders = Orders[Status in {"New","Open","Held","Review","Approved","Packed","Shipped"}];
Works
active_statuses = {"New","Open","Held","Review","Approved","Packed","Shipped"};
orders = Orders[Status in active_statuses];
Zoho docs: Criteria
DLG101 Error Checks your app's schema Criteria variable shadows a field of the queried form
Inside Form[...], an identifier equal to a field link name of that form refers to the field, not your variable or parameter, so Orders[ID == order_id] compares the field order_id to itself. Rename variables used in criteria (suffix _param, _value or _filter). On code Creator already saved (the mirror) it is reported as a warning: the filter silently matches every record; fix it when you next touch the function.
Example
Fails
void Orders.Close(int order_id)
{
order = Orders[ID == order_id];
}
Works
void Orders.Close(int order_id_param)
{
order = Orders[ID == order_id_param];
}
DLG107 Error Checks your app's schema Multi-select lookup membership uses Field.contains(id)
Form[Multi contains x] and Form[x in Multi] fail for multi-select lookups. Use Form[Multi.contains(record_id)] (the production idiom) with a Creator record ID. Zoho's criteria table documents ==, !=, in and not in with a LIST of record IDs on the field side (Form[Multi in id_list]); both forms are acceptable. Never put the field on the right of in.
Example
Fails
orders = Orders[Products contains product_id_param];
Works
orders = Orders[Products.contains(product_id_param)];
DLG116 Error Checks your app's schema Text methods on a lookup value
Lookup fields hold record IDs (numbers). Calling .contains("…") or .startsWith on them, or comparing them to display text, is invalid. Compare IDs or traverse to a text field.
Example
Fails
acme_orders = Orders[Customer.contains("Acme")];
Works
acme_orders = Orders[Customer.Company_Name.contains("Acme")];
DLG124 Error Checks your app's schema Unsupported operator on an encrypted field
Fields with data encryption support only ==, != and isEmpty() in criteria.
Example
Fails
matches = Customers[Tax_Number.startsWith("12")];
Works
matches = Customers[Tax_Number == tax_number_param];
Zoho docs: Criteria
DLG125 Error Checks your app's schema sort by a field that can't be sorted
Records can't be sorted by Multi Select, Multi Select lookup, Checkbox, subform, Name or Address (composite) fields, nor by Added_Location or Modified_Location.
Example
Fails
orders = Orders[Status == "Open"] sort by Products;
Works
orders = Orders[Status == "Open"] sort by Order_Date desc;
Zoho docs: Fetch records
Records 5
update Form[criteria] [...] updates only the first match
The update-multiple-fields task on a filtered form updates the first matching record only. Use an ID criteria, or loop over the records.
Example
Fails
update Orders[Status == "Open" && Due_Date < zoho.currentdate]
[
Status = "Overdue"
];
Works
for each late_order in Orders[Status == "Open" && Due_Date < zoho.currentdate]
{
update late_order
[
Status = "Overdue"
];
}
Zoho docs: Update multiple fields
Don't write system or computed fields
ID, Added_Time, Modified_Time, Modified_User, the IP and location system fields, Auto Number and Formula fields are set by Creator and can't be assigned in insert or update or with rec.Field = …. There is no Created_At system field.
Example
Fails
order.Modified_Time = zoho.currenttime;
Works
order.Last_Reviewed_At = zoho.currenttime;
Zoho docs: Add records, Update records
DLG117 Error Checks your app's schema insert without every mandatory field
An insert must supply every mandatory field of the target form or it fails at runtime.
Example
Fails
new_id = insert into Orders
[
Status = "Open"
];
Works
new_id = insert into Orders
[
Customer = customer_id_param
Order_Date = zoho.currentdate
Status = "Open"
];
Zoho docs: Add records
DLG118 Error Checks your app's schema Write to an Auto Number, Formula or other read-only field
Auto Number, Formula and Signature fields can't be set from Deluge; Add Notes fields can't be written by insert or update or on a fetched record, and subform fields can't be set by an update. A form workflow may rewrite an Add Notes field on screen with input.<Note_Field> = "…" (not flagged).
Example
Fails
order_rec.Order_Number = "ORD-1001";
Works
order_rec.External_Ref = "ORD-1001";
Zoho docs: Update records
DLG119 Warning Checks your app's schema Writing a value that isn't a configured choice
Deluge writes to Drop Down, Radio and Multi Select fields accept any text and store it silently (the choice isn't added to the field). A literal that isn't one of the field's choices is usually a typo.
Example
Fails
order_rec.Status = "Shiped";
Works
order_rec.Status = "Shipped";
Zoho docs: Add records
Collections 5
Sort record collections with sort by, not .sort()
A fetch is sorted in the fetch itself: Form[criteria] sort by Field [desc]. .sort(…) is a List method.
Example
Fails
recent = Orders[Customer == customer_id_param].sort(Order_Date, false);
Works
recent = Orders[Customer == customer_id_param] sort by Order_Date desc;
Zoho docs: Fetch records
List("a","b") is not a list constructor
List() creates an empty list; List(text) splits one comma-separated text. Use a literal {"a","b"} for known elements.
Example
Fails
statuses = List("Open", "On Hold");
Works
statuses = {"Open","On Hold"};
Zoho docs: Create a list
DLG109 Warning Checks your app's schema .size() for lists, .count() for record collections
Multi-select and multi-lookup values and other lists use .size(); fetch results use .count(). Mixing them errors (Creator: 'Collection expected, found List').
Example
Fails
if(order_rec.Products.count() > 0)
{
info "has products";
}
Works
if(order_rec.Products != null && order_rec.Products.size() > 0)
{
info "has products";
}
DLG111 Warning Checks your app's schema Dot access on a Map
Maps (Map(), {…}, toMap(), JSON responses) are read with .get("key"); m.key is invalid. Dot access is for records.
Example
Fails
response_map = response_text.toMap();
status_value = response_map.status;
Works
response_map = response_text.toMap();
status_value = response_map.get("status");
DLG126 Info Checks your app's schema Iterating a multi-select lookup field as if it held records
A multi-select lookup field is a list of record IDs. Iterating it yields IDs; fetch the records with Form[ID in rec.Field] first. Production code reads fields of the loop variable while iterating a multi-select lookup; verify before rewriting.
Example
Fails
for each product_rec in order_rec.Products
{
info product_rec.Product_Name;
}
Works
for each product_rec in Products[ID in order_rec.Products]
{
info product_rec.Product_Name;
}
Strings 6
No .split(): use toList(separator)
Text has no split() method. text.toList(sep) splits; getPrefix, getSuffix, indexOf and subString cover single cuts.
Example
Fails
parts = email_text.split("@");
Works
parts = email_text.toList("@");
Zoho docs: toList()
urlEncode() is zoho.encryption.urlEncode()
A bare urlEncode(x) call fails (Creator: 'Not able to find 'urlEncode' function'). Use zoho.encryption.urlEncode(x) (space becomes %20) or encodeUrl(x) (space becomes +).
Example
Fails
link = "#Report:All_Orders?Status=" + urlEncode(status_value);
Works
link = "#Report:All_Orders?Status=" + zoho.encryption.urlEncode(status_value);
Zoho docs: zoho.encryption.urlEncode(), encodeUrl()
replaceAll treats the search text as a regex
replaceAll and replaceFirst use regular expressions by default; . matches any character and +, *, ?, (, [, |, $, ^, \ are metacharacters. Pass true as the third argument for a literal search.
Example
Fails
safe_name = file_name.replaceAll(".", "_");
Works
safe_name = file_name.replaceAll(".", "_", true);
Zoho docs: replaceAll()
getPrefix/getSuffix return null when the separator is missing
Chaining a method on getPrefix() or getSuffix() fails at runtime when the separator isn't there (Creator: 'Null value occurred…'). Check for null or wrap it with ifnull.
Example
Fails
domain = email_text.getSuffix("@").toLowerCase();
Works
domain = ifnull(email_text.getSuffix("@"), "").toLowerCase();
Zoho docs: getSuffix()
subString/left/right with a fixed bound on variable text
subString(start, end) errors when an index is past the end of the text (Creator: 'Given string is lesser than the applied boundary…'). Clamp it with min(text.length(), n).
Example
Fails
preview = body_text.subString(0, 500);
Works
preview = body_text.subString(0, min(body_text.length(), 500));
Zoho docs: subString()
zoho.encryption.urlDecode() is not available in Creator
Zoho documents urlDecode as unavailable in Creator, but zoho.encryption.urlDecode() saves in Creator code that runs in production. Verify it at runtime, or avoid needing it: keep raw values unencoded and encode only at the boundary.
Example
Fails
status_value = zoho.encryption.urlDecode(encoded_status);
Works
link = "#Page:Order_Dashboard?status_filter=" + zoho.encryption.urlEncode(status_value);
Zoho docs: zoho.encryption.urlDecode()
Dates and times 3
Date-time methods that don't exist
toStartOfDay, startOfDay, truncate, setHour, withTime, midnight, minutesBetween and secondsBetween do not exist. Midnight: d.toString("dd-MMM-yyyy").toDateTime(); elapsed minutes: ((b.toLong() - a.toLong()) / 60000).toLong().
Example
Fails
minutes_open = opened_at.minutesBetween(zoho.currenttime);
day_start = zoho.currenttime.toStartOfDay();
Works
minutes_open = ((zoho.currenttime.toLong() - opened_at.toLong()) / 60000).toLong();
day_start = zoho.currenttime.toString("dd-MMM-yyyy").toDateTime();
Zoho docs: Date-time functions
Date-time method singular/plural spelling
addDay, addHour, addWeek, addMonth, addYear and subDay, subHour, … are singular; addMinutes, addSeconds, subMinutes and subSeconds are plural. addMinute, addDays, addHours, addSecond, subDays, subHours, subMinute, addWeeks, addMonths and addYears don't exist.
Example
Fails
remind_at = zoho.currenttime.addMinute(30);
due_at = zoho.currenttime.addDays(3);
Works
remind_at = zoho.currenttime.addMinutes(30);
due_at = zoho.currenttime.addDay(3);
Zoho docs: Date-time functions
DLG108 Error Checks your app's schema Date/Date-Time compared with ""
Date values are null or a date; comparing them to "" is a type mismatch. Check != null only.
Example
Fails
if(order_rec.Due_Date != null && order_rec.Due_Date != "")
{
info "has due date";
}
Works
if(order_rec.Due_Date != null)
{
info "has due date";
}
Pages 5
No HTML or <% %> in a page script
The page script is pure Deluge; markup and <% %> templating belong in the HTML snippet element.
Example
Fails
open_count = Orders[Status == "Open"].count();
<div><%=open_count%></div>
Works
open_count = Orders[Status == "Open"].count();
A // comment must not run up to %> in an HTML snippet
Inside <% %> blocks of an HTML snippet, a // comment that runs up to the closing %> on the same line can swallow the code Creator generates after the block (Creator: 'Improper Statement (missing ;)'). A // comment on its own line inside a multi-line block saves and runs; end the comment with a line break, or use /* */.
Example
Fails
<%{%>
<%
for each row_map in input.status_rows
{ // one row per status %>
<li><%=row_map.get("status")%></li>
<%
}
%>
<%}%>
Works
<%{%>
<%
for each row_map in input.status_rows
{ /* one row per status */ %>
<li><%=row_map.get("status")%></li>
<%
}
%>
<%}%>
HTML snippet with Deluge blocks lacks the <%{%> … <%}%> wrapper
Some apps need the whole snippet wrapped in <%{%> … <%}%> for <% %> blocks to run. Add it when a snippet contains Deluge blocks.
Example
Fails
<ul>
<% for each row_map in input.status_rows { %>
<li><%=row_map.get("status")%></li>
<% } %>
</ul>
Works
<%{%>
<ul>
<% for each row_map in input.status_rows { %>
<li><%=row_map.get("status")%></li>
<% } %>
</ul>
<%}%>
Page script input.* values are read-only
In page scripts, input.<var> holds page variables and URL parameters; copy it into a local variable before transforming it. (HTML and ZML snippets may assign input.<param> inside <% %> to give a parameter a default and read it back with <%=input.param%>; that saves and runs, so snippets are not flagged.)
Example
Fails
input.status_filter = "Open";
Works
status_value = ifnull(input.status_filter, "Open");
List methods on collection page variables
Collection page variables don't distinguish lists and maps; .add() and .remove() on them fail (Creator: '…applicable for LIST expression, but … is of type COLLECTION'). Build a local List() or Map() and assign it to the page variable at the end.
Example
Fails
status_rows.add("Open");
Works
rows_local = List();
rows_local.add("Open");
status_rows = rows_local;
Workflows 4
Client functions only in form events
alert, hide, show, enable, disable, clear, select/deselect, :ui.add, cancel submit, openUrl and reload work in form events (load, user input, validate, field rules). They are invalid in custom functions, schedules, batch workflows and page scripts.
Example
Fails
void Orders.Recalculate(int order_id_param)
{
alert "Recalculated";
}
Works
void Orders.Recalculate(int order_id_param)
{
info "Recalculated " + order_id_param;
}
Zoho docs: Client functions: alert
DLG120 Info Checks your app's schema Deluge insert skips the target form's On Validate / On Success
Records created with insert into don't run the target form's On Validate and On Success workflows. If that form has such workflows, call their shared function explicitly.
Example
Fails
new_id = insert into Orders
[
Customer = customer_id_param
Status = "Open"
];
Works
new_id = insert into Orders
[
Customer = customer_id_param
Status = "Open"
];
thisapp.Orders.After_Save(new_id);
Zoho docs: Add records
DLG121 Warning Checks your app's schema A date-field schedule's run edits its own trigger field
A 'once' schedule on a Date-Time field does not reschedule when its own run modifies that field (documented). Arm the next run by inserting a new record (a queue item or step row), or let a separate sweeper re-arm it.
Example
Fails
void Tasks.Send_Reminder(int task_id_param)
{
task_rec = Tasks[ID == task_id_param];
task_rec.Remind_At = zoho.currenttime.addDay(1);
}
Works
void Tasks.Send_Reminder(int task_id_param)
{
task_rec = Tasks[ID == task_id_param];
task_rec.Reminder_Status = "Sent";
next_id = insert into Task_Reminders
[
Task = task_id_param
Remind_At = zoho.currenttime.addDay(1)
Reminder_Status = "Scheduled"
];
}
DLG122 Warning Checks your app's schema Trigger time set to now (or the past)
Date-field triggers set to zoho.currenttime can be missed if the record saves after that instant, and past values may never fire. Use at least zoho.currenttime.addMinutes(1) and pair it with a stale sweeper.
Example
Fails
item_rec.Run_At = zoho.currenttime;
Works
item_rec.Run_At = zoho.currenttime.addMinutes(1);
Security 5
No credentials in invokeurl URLs
Credentials embedded in invokeurl URLs (user:pass@host, api_key, token or secret query parameters) were deprecated on 2025-09-30. Use a Connection (connection: "name").
Example
Fails
response = invokeurl
[
url: "https://api.example.com/v1/orders?api_key=abc123"
type: GET
];
Works
response = invokeurl
[
url: "https://api.example.com/v1/orders"
type: GET
connection: "example_api"
];
Zoho docs: Deluge release notes, Connections
Authorization headers built in code instead of a Connection
Setting Authorization or X-API-Key headers yourself means a credential lives in code or data. Prefer a Connection (OAuth 2, API key, Basic, AWS SigV4) and pass connection:.
Example
Fails
headers = Map();
headers.put("Authorization", "Bearer " + api_token);
response = invokeurl
[
url: "https://api.example.com/v1/orders"
type: GET
headers: headers
];
Works
response = invokeurl
[
url: "https://api.example.com/v1/orders"
type: GET
connection: "example_api"
];
Zoho docs: Connections
External side effects without an environment guard
In apps that use environments, development and stage share code with production. Guard live HTTP calls, emails and payments with thisapp.environment.type == "production" (or a config flag).
Example
Fails
response = invokeurl
[
url: "https://payments.example.com/v1/capture"
type: POST
connection: "payments_api"
];
Works
if(thisapp.environment.type == "production")
{
response = invokeurl
[
url: "https://payments.example.com/v1/capture"
type: POST
connection: "payments_api"
];
}
Zoho docs: Environment attributes
Hard-coded secret in code
Tokens, API keys, passwords, client secrets and secret webhook URLs must not be literals in Deluge (visible to every developer, exported in .ds files and backups, sent to AI tools). Use Connections or an admin-only encrypted settings field.
Example
Fails
headers = Map();
headers.put("Authorization", "Bearer 4f9c2e7a1b3d5f60a8c4e2d1");
Works
response = invokeurl
[
url: "https://api.example.com/v1/charges"
type: GET
connection: "payments_api"
];
Secret placeholder would reach Creator unrehydrated
A ZENITH_SECRET_<hex8> placeholder in code bound for Creator must be restored from the vault for this component; otherwise Creator would store the placeholder instead of the secret.
Example
Fails
headers.put("Authorization", "Bearer ZENITH_SECRET_0a1b2c3d");
Works
response = invokeurl
[
url: "https://api.example.com/v1/x"
type: GET
connection: "example_api"
];
Maintainability 2
Hard-coded record IDs
Long numeric record IDs in logic differ between environments and app copies and hide intent. Read them from config, a lookup, or a query by business key.
Example
Fails
manager_rec = Users_Directory[ID == 4123870000000215027];
Works
config = thisapp.App_Config.Get();
manager_rec = Users_Directory[ID == config.get("default_manager_id")];
DLG123 Info Checks your app's schema New code depends on a component marked legacy
When the project marks forms or functions as legacy or deprecated, new code should not call or extend them without an explicit decision.
Example
Fails
thisapp.Legacy_Billing.Post_Invoice(invoice_id);
Works
thisapp.Billing.Post_Invoice(invoice_id);
No rules match that filter.