Skip to main content
View Markdown

Troubleshooting

Start from the symptom. Before changing code, identify the execution context, because the same symptom has different causes in different contexts. Evidence labels have the same meaning as on that page.

Blank weblet​

Likely causes

  • The frame request failed with 401 or 403, or the app is inactive.
  • The weblet is on a .form view, where plain output is discarded.
  • The asset has no deployed code, so the platform returns an empty response.
  • Output text was discarded by result propagation.
  • A script error occurred after the frame loaded.

How to confirm

  1. Open browser developer tools and find the request for the frame.
  2. Read its status and response body. Status 200 with an empty body means the script produced nothing.
  3. Check the view ending and the type in the manifest.
  4. Run zeysdk compare to confirm that the deployed code matches yours.

Fix

Correct the status cause, deploy the code, or move the weblet to a view that matches how it renders. Use form commands in .form views and output elsewhere. zeysdk run cannot reproduce this problem, because it has no session and no frame.

A protected route accepts a request with no token​

Likely causes

  • The handler reads AUTH without <use var="AUTH" />, so a query argument or form field supplies it.
  • The check sits before rest:server, and the handler still reads a forgeable $AUTH.*.
  • The handler has no check. The platform does not reject anonymous calls for you, even for a restricted application.

How to confirm

Send ?AUTH[user]=1 with no token, using curl -g. A 200 confirms the problem.

Fix

Add use as the first child of every rest:resource, for every global the handler reads. See Bind globals inside rest:resource. Treat any past use of such a route as unauthenticated.

Unauthenticated or forbidden service call from a weblet​

Likely causes

  • The weblet's JavaScript called REMOTECALL, and the cookie does not authenticate that call, so AUTH is unset.
  • The Authorization header holds an SDK token, not an access token.
  • The application is restricted and the token's user lacks permission, which gives 403. An anonymous call is not stopped by this check and still runs.
  • The service or application is inactive, which also gives 403.

How to confirm

Inspect the failing request in developer tools and check for an Authorization header. Repeat the call with curl and a known-good access token. If that works, the service is fine and the browser call is the problem.

Fix

Prefer calling the resource server-side from the weblet, as the minimal app does. If the browser must call the service, follow the design requirements. Do not remove the service's check, and do not treat CORS as the cause or the fix. The response is already open to every origin.

Wrong include target or type​

Likely causes

  • The identifier is misspelled, or its . prefix was dropped.
  • The target is a service or weblet, but include defaulted to resource.
  • The target exists locally but has not been deployed. include resolves on the instance.
  • The script has no app namespace, so .name cannot resolve.

How to confirm

The error names the type and identifier it looked for, as written in the include, for example Unable to load enhancement "resource:.api" in INCLUDE. Compare that with the manifest. A compile pass does not check this.

Fix

Correct the identifier, push the target, or set the type (Reference):

XML
<include id=".api" type="service" />

Already-decoded JSON​

Likely causes

The value came from an application/json resource, which include returns decoded. decode:json then receives an array instead of a string.

How to confirm

Check the resource's mimetype in the manifest. Inspect the value with typeof:

XML
<include id=".defaults" var="defaults" />
<typeof var="defaults" var_result="kind" />
<output>$kind</output>

Fix

Delete the decode:json. The reverse problem also exists: a JSON request body arrives as a string, so read it with var_body and decode it inside try. See Includes and JSON resources.

Missing or empty session locale​

Likely causes

  • The code reads $session.lang. The locale is in $session.data.lang (Source-confirmed).
  • There is no session user and no valid cookie, as in TIMING or zeysdk run.
  • The code runs in a hook or in REMOTECALL, where the result depends on what triggered it. Do not rely on session there.

How to confirm

Check the context. session returns NULL without a session (Reference). To check the value on a sandbox, output the named key, such as $session.data.lang, from a weblet.

warning

Never dump the whole session array. It can include credential columns from the user record.

Fix

Use $AUTH.lang in REMOTECALL and always provide a fallback:

XML
<session var="session" />
<set var="lang">$session.data.lang</set>

<if value1="$lang" value2="">
<set var="lang">en_US</set>
</if>

Empty lint selection​

Symptom: zeysdk lint prints No modified iXML or Zymba files to lint. and exits 0.

Likely causes

  • Nothing differs from the last synchronized state, for example straight after a push.
  • The changed script is not registered in the manifest.

How to confirm

Run zeysdk lint --all and read the file list. Check that your file appears.

Fix

Compile the file directly with zeysdk compile <path>, or register it. Record an empty selection as no files checked, never as a pass.

Uncertain completion after a timeout​

Symptom: Request timed out after 30000ms, or a dropped connection, during run or push.

Likely causes

The client stopped waiting. That shows nothing about the server, which may have finished, may still be running, or may have stopped. See Timeouts and uncertain completion.

How to confirm

Check the effects directly: records, mail, external systems, and the platform log. After a push, run zeysdk compare.

Fix

Do not retry blindly. The SDK's request layer does not resend these requests, so a second run is a second execution. zeysdk watch does retry a failed push on its own, so stop it first. Make long work idempotent and resumable, and move it to a TIMING service.

Text disappears from output​

Symptom: <output> shows only part of what you wrote.

Cause: literal text used alongside an embedded statement is discarded (Reference). Logged on 6 February 2026: <output><set>$(15 + (7.5 * 2 - 3))</set>471</output> returned 27, not 27471.

Fix: assign to a variable first, then substitute it.

XML
<!-- Wrong: "Hello" is discarded -->
<output>Hello <encode:html>$name</encode:html></output>

<!-- Right -->
<encode:html var="safeName">$name</encode:html>
<output>Hello $safeName</output>

See Result propagation.

replace changes nothing or the wrong text​

Cause: in replace, value is the search value. The new text goes in replacement, and the subject is the element content (Reference).

XML
<replace value="Bill Gates" replacement="William Henry Gates III">My name is Bill Gates!</replace>

A route works over HTTP but returns 404 in zeysdk run​

Cause: this is expected. The console has no inbound route and its requests use PUT, so GET and POST routes do not match. Logged on 6 February 2026: HTTP 404 and null.

Fix: test the route with an HTTP request. See Checkpoint 4.

Reported, not independently verified — check in your target​

These items come from an app build reported in November 2026. They were not reproduced for this guide, and none of them is established behavior. Test each one on your target before relying on either the report or the safe form.

ReportWhat the reference saysHow to checkConservative form
After assign, array:merge on the copy also changed the source arrayComplex variables are assigned by reference, and array:merge is destructive unless var_result is setAssign, merge, then print the sourceMerge with var_result, or use clone
JSON false and a missing key both read as an empty valueis separates defined, false, and empty. array:keyexists tests for a keyDecode {"a":false} and compare $data.a with $data.bUse array:keyexists for presence and is for type
No rounding inside $( ), and empty operands break arithmeticmath:round exists. Uninitialized variables default to the neutral literalCompare math:round with an inline expression on sample valuesUse math:round, and default empty operands to 0 first
db:is with an empty value on an integer column failsNot statedOn a sandbox, run a read with an empty valueCheck the value with is type="empty" before adding the condition
An embedded weblet with height 0 sizes itself to its contentNot statedRegister a test weblet and resize its contentSet an explicit height until confirmed on your target