---
title: "Troubleshooting"
description: "Symptoms, likely causes, confirmation steps, and fixes for common ZeyOS app problems."
canonical_url: "https://www.zeyos.com/ixml/ixml-guide/development-environment/troubleshooting"
markdown_url: "https://www.zeyos.com/ai/guide/ixml/ixml-guide/development-environment/troubleshooting.md"
section: "ixml-guide"
authority: "guide"
language: "en"
source_repository: "zeyos/guide"
source_path: "docs/ixml/03-development-environment/troubleshooting.md"
source_revision: "cce886a8da98cd124ee3644711085bbdcf1a87ce"
---

# Troubleshooting

Start from the symptom. Before changing code, identify the [execution context](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts), 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](#text-disappears-from-output).
- 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`](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts#bind-globals-inside-restresource). 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](https://www.zeyos.com/ixml/ixml-guide/development-environment/minimal-app#weblet) does. If the browser must call the service, follow the [design requirements](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts#calling-your-own-service-from-a-weblet). 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](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts#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](https://www.zeyos.com/ixml/ixml-guide/development-environment/verification-checkpoints#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](https://www.zeyos.com/ixml/ixml-guide/introduction/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](https://www.zeyos.com/ixml/ixml-guide/development-environment/verification-checkpoints#checkpoint-4-runtime-verification).

## 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.

| Report | What the reference says | How to check | Conservative form |
| --- | --- | --- | --- |
| After `assign`, `array:merge` on the copy also changed the source array | Complex variables are assigned by reference, and `array:merge` is destructive unless `var_result` is set | Assign, merge, then print the source | Merge with `var_result`, or use `clone` |
| JSON `false` and a missing key both read as an empty value | `is` separates `defined`, `false`, and `empty`. `array:keyexists` tests for a key | Decode `{"a":false}` and compare `$data.a` with `$data.b` | Use `array:keyexists` for presence and `is` for type |
| No rounding inside `$( )`, and empty operands break arithmetic | `math:round` exists. Uninitialized variables default to the neutral literal | Compare `math:round` with an inline expression on sample values | Use `math:round`, and default empty operands to `0` first |
| `db:is` with an empty value on an integer column fails | Not stated | On a sandbox, run a read with an empty value | Check the value with `is type="empty"` before adding the condition |
| An embedded weblet with height `0` sizes itself to its content | Not stated | Register a test weblet and resize its content | Set an explicit `height` until confirmed on your target |

## Related topics

- [Execution Contexts](https://www.zeyos.com/ixml/ixml-guide/development-environment/execution-contexts)
- [Verification Checkpoints](https://www.zeyos.com/ixml/ixml-guide/development-environment/verification-checkpoints)
- [Minimal App](https://www.zeyos.com/ixml/ixml-guide/development-environment/minimal-app)
- [Debugging](https://www.zeyos.com/ixml/ixml-guide/error-handling/debugging)
