> ## Documentation Index
> Fetch the complete documentation index at: https://docs.omnilinker.pl/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshoot ERP sync

> Find out why the ERP Sync agent is offline or why changes from your ERP are not arriving, and fix it.

Start with the quick checks, then open the entry that matches what you see. Run the PowerShell commands on the agent
computer.

## Quick checks

```powershell theme={null}
# Is the Windows service running?
Get-Service OmnilinkerErpSyncService

# What does the agent report? (state 0 = Idle, 1 = Syncing, 2 = Paused, 3 = Error)
Invoke-RestMethod -Headers @{ "X-Omnilinker-Local" = "1" } http://localhost:5555/api/sync/status |
  Select-Object state, isConnected, isErpConnected, lastError, waitingReason

# Are events waiting to be sent to Omnilinker?
Invoke-RestMethod -Headers @{ "X-Omnilinker-Local" = "1" } http://localhost:5555/api/sync/outbox/stats

# Can this computer reach Omnilinker?
Test-NetConnection omnilinker.pl -Port 443
```

In Omnilinker, open **ERP Integration** > **Connections**, open the connection and check its **Agent** tab. See
[Monitoring](/erp/monitoring#agent-tab).

* `isConnected: False`: the agent cannot talk to Omnilinker, or Omnilinker rejects it.
* `isErpConnected: False`: the agent cannot read the ERP database.
* `pending` growing in the outbox stats: changes are detected but not delivered.

The status fields are described in the [local API reference](/erp/local-api).

## Common problems

<AccordionGroup>
  <Accordion title="Where are the logs?">
    The agent has two logs.

    **Service log files.** The Windows service writes one file per day and keeps the last 30:

    ```text theme={null}
    %ProgramData%\Omnilinker\ErpSync\logs\erpsync-<yyyyMMdd>.log
    ```

    That is usually `C:\ProgramData\Omnilinker\ErpSync\logs`. Everyone signed in to the computer can read it. To
    follow today's file:

    ```powershell theme={null}
    Get-Content "$env:ProgramData\Omnilinker\ErpSync\logs\erpsync-$(Get-Date -Format yyyyMMdd).log" -Tail 50 -Wait
    ```

    In the tray app, **Open logs folder** in **Settings…** or **Troubleshoot…** opens the same folder.

    **Setup log.** Setup, updates and uninstalling write what they could not do to `setup.log` in the same folder.
    See **Setup finished, but there is no service**.

    **Sync log.** The agent also keeps a short log of sync events in its local database. Read it in the tray app in
    **Sync details…** > **Activity**, or with `GET /api/sync/logs` on the [local API](/erp/local-api).

    The agent does not write its own messages to the Windows event log. Windows records service start failures in
    the System log (see the next entry).
  </Accordion>

  <Accordion title="The service does not start">
    `Get-Service OmnilinkerErpSyncService` shows `Stopped`, or the service stops shortly after it starts. The tray
    icon shows a red square, and its tooltip says **The ERP Sync service isn't running**.

    The service is set to restart itself after a failure (after 5, 10 and 30 seconds), so a service that keeps
    stopping has a problem that a restart does not fix.

    1. Open **Event Viewer** > **Windows Logs** > **System** and look for errors from the source **Service Control
       Manager** that name **Omnilinker ERP Sync** (**Omnilinker ERP Sync Service** on an installation made with
       `install-service.ps1`). For a crash, also check **Windows Logs** >
       **Application** for **.NET Runtime** or **Application Error** entries.
    2. Open the newest service log file (see **Where are the logs?**). If the service started far enough to log, the
       last lines say why it stopped. A fatal start-up error ends with
       `Omnilinker ERP Sync Service terminated unexpectedly`.

    Common causes:

    * **Logon failure.** Someone changed the service to run under another account, and its password changed. The
      System log says the service did not start due to a logon failure. Open **Services**, open
      **Omnilinker ERP Sync** > **Log On**, select **Local System account** and click **OK**. The agent is designed
      to run as Local System.
    * **Port 5555 in use.** See **The local API port is already in use**.
    * **Broken `appsettings.json`.** If you edited it, check that it is still valid JSON. From the install folder:

      ```powershell theme={null}
      Get-Content .\appsettings.json -Raw | ConvertFrom-Json
      ```

      An error means the file is not valid. Fix it or restore it from the original package.

    Start the service again after a fix, in PowerShell as Administrator:

    ```powershell theme={null}
    Start-Service OmnilinkerErpSyncService
    ```
  </Accordion>

  <Accordion title="Setup finished, but there is no service">
    Setup completed, but `Get-Service OmnilinkerErpSyncService` finds no service, or the tray app does not start at
    sign-in. Setup never fails because of one step; it writes what it could not do to
    `%ProgramData%\Omnilinker\ErpSync\logs\setup.log`:

    ```powershell theme={null}
    Get-Content "$env:ProgramData\Omnilinker\ErpSync\logs\setup.log" -Tail 20
    ```

    | Line in `setup.log` | What to do |
    | - | - |
    | `not registering the service: <path> is inside a user's profile. Install for all users.` | The agent was installed into a user profile, for example by double-clicking the installer. Uninstall it, then install it again with `--installto`. See [Install the agent](/erp/install-agent#install-the-agent). |
    | `data folder:`, `operators group:`, `service:`, `tray at sign-in:` or `start service:` followed by an error, such as `exit code 5` | Setup could not do that step, most often because it did not run as an administrator. Run the same setup command again from PowerShell as Administrator. |
    | `done` | Every step succeeded. |

    If there is no `setup.log` at all, setup could not even create the folder. Run it again from PowerShell as
    Administrator.
  </Accordion>

  <Accordion title="The tray app cannot reach the service">
    The tooltip says **The ERP Sync service isn't running**, or setup shows "The Omnilinker ERP Sync service isn't
    running." or "The Omnilinker ERP Sync service is running but doesn't answer."

    1. Open **Troubleshoot…** in the tray app. When the service does not answer, it looks at the Windows service
       itself and offers the fix that fits, with an administrator's approval:

       * **Restart service**, when the service is stopped, or running but not answering. Changes wait in the ERP
         meanwhile, so nothing is lost.
       * **Repair**, when the Windows service is missing or runs another copy of the agent. It sets the service up
         again for this installation and keeps the connection and its settings.

       On a copy not installed with the MSI, it offers **Open Windows services** instead. If the service keeps
       stopping, see **The service does not start**.
    2. If the tray app shows "Something other than the ERP Sync service answered. Restart the PC; if it happens
       again, contact support.", another program answered on the agent's pipe. The tray app talks only to the
       Windows service. Restart the computer.
  </Accordion>

  <Accordion title="The tray app says Only an operator of this PC can do this">
    You can see the agent's status, but setup, changing the database, pausing, or turning instant change detection
    on or off fails with "Only an operator of this PC can do this: a member of “Omnilinker ERP Sync Operators”, or an
    administrator."

    Your Windows account is not allowed to change the agent. Ask an administrator of the computer to add you to the
    local group **Omnilinker ERP Sync Operators**, then try again. You do not need to sign out. See
    [Who can change the agent](/erp/install-agent#who-can-change-the-agent).

    An administrator can also close the tray app (**Hide the tray icon**) and start it again with **Run as
    administrator**.
  </Accordion>

  <Accordion title="The local API answers 403 Forbidden">
    A script or monitoring tool gets `403 Forbidden` with an empty body from `http://localhost:5555/api/...`.

    * Add the header `X-Omnilinker-Local: 1` to every request. See [Local API](/erp/local-api#access-and-security).
    * Call the API as `localhost`, `127.0.0.1` or `[::1]`, not by the computer's name.
    * From a web page, only Omnilinker's own pages may call the API.
  </Accordion>

  <Accordion title="The local API port is already in use">
    The service stops right after it starts. Its log file contains a line like
    `Failed to bind to address http://127.0.0.1:5555: address already in use`.

    Another program uses port 5555 on the agent computer. Find it:

    ```powershell theme={null}
    Get-NetTCPConnection -LocalPort 5555 -State Listen |
      ForEach-Object { Get-Process -Id $_.OwningProcess }
    ```

    Stop that program or move it to another port, then start the service.

    You can move the agent to another port with `LocalApiPort` in `appsettings.json`, but the web app's **Local
    Service** tab keeps using port 5555 and will not reach the agent. Free
    port 5555 if you can. See the [configuration reference](/erp/configuration-reference).
  </Accordion>

  <Accordion title="The Agent tab says Offline">
    **Offline** means Omnilinker has not received a heartbeat for more than 3 minutes. **Last heartbeat** shows when
    the last one arrived. A running, accepted agent sends one every 60 seconds.

    Work through these in order:

    1. **Is the service running?** See **The service does not start**.
    2. **Can the agent reach Omnilinker?** See **The agent cannot reach omnilinker.pl**.
    3. **Is the connection active?** On **ERP Integration** > **Connections**, the connection's **Status** must be
       **Active**. Omnilinker rejects heartbeats and changes for an inactive connection. To switch it on, click
       **Activate** in the row's **Actions** menu.
    4. **Is the API key still valid?** See **The API key is rejected**.
    5. **Is the agent too old?** See **Omnilinker rejects the agent version**.

    If the tab says **No agent has connected yet**, the agent has never reached Omnilinker with this connection's key.
    Complete [setup](/erp/setup-wizard) on the agent computer.
  </Accordion>

  <Accordion title="The API key is rejected">
    The agent's log shows, repeatedly:

    ```text theme={null}
    Authentication failed for connection <connection-id>. Status: Unauthorized. Please verify API key is valid and not expired.
    Heartbeat returned Unauthorized for connection <connection-id>
    ```

    In the tray app, the icon shows a red square and the panel says **Omnilinker doesn't accept this PC.**

    The agent's key no longer works. Most often the connection got a new agent key: someone clicked **Generate Agent
    Key** on the connection again, or connected another computer to it. Either revokes the previous key straight
    away.

    To fix it, connect this computer again:

    1. In Omnilinker, open the connection and get a connection code with **Connect a PC**. See
       [Get a connection code](/erp/setup-wizard#get-a-connection-code).
    2. On the agent computer, click **Connect again** in the tray app's panel (or **Settings…** > **Connect to
       another company…**) and complete [setup](/erp/setup-wizard) with the code.

    To use an API key instead, generate one with **Generate Agent Key** in the row's **Actions** menu (it is shown
    only once, see [Create a connection](/erp/create-connection)), and click **Use an API key instead** in setup.
    Generating a key again revokes the one you just made too, so do it only once and enter the new key in setup
    straight away.

    Related messages:

    * "Omnilinker doesn't know that API key. Check it, or create a new one." (in setup): the key is mistyped or no
      longer valid.
    * "That API key isn't allowed to sync an ERP. Use a key of the ERP connection." (in setup): the key is not an
      agent key. Use a key from **Generate Agent Key**, not one from the Administration API keys page.
    * "This agent key is not authorized for the requested ERP connection." The key belongs to a different
      connection. Run setup again and choose the right connection, or generate a key on this connection.

    `Status: Forbidden` in the first message above is not a key problem. See **Omnilinker rejects the agent version**
    and **Changes are not arriving**.
  </Accordion>

  <Accordion title="Omnilinker rejects the agent version">
    Omnilinker can require a minimum agent version. When your agent is older, Omnilinker rejects every request from it
    with:

    ```text theme={null}
    Agent version <version> is no longer supported (minimum supported version: <minimum>). Please update the ERP Sync agent.
    ```

    What you see:

    * In Omnilinker, the connection's **Agent** tab turns **Offline** and **Last heartbeat** stops moving.
      **Agent version** still shows your old version.
    * In the agent's log, `Heartbeat returned Forbidden`, and `Cloud API returned Forbidden for batch publish:`
      followed by the message above. The configuration check also logs `Authentication failed ... Status: Forbidden`,
      even though the key is fine.
    * The outbox `pending` count grows, and later `failed` grows too.

    The agent [updates itself](/erp/install-agent#update-the-agent) at night when a newer version is published, so
    this should clear by itself. If it does not, check that automatic updates are on (`AutoUpdateEnabled`) and that
    the agent computer can reach `releases.omnilinker.com`, or run the new installer by hand.

    Do it promptly. Each rejected send counts as a failed attempt, and changes that fail every attempt are not sent
    again (see **Changes are not arriving**).
  </Accordion>

  <Accordion title="The agent cannot reach omnilinker.pl">
    The status shows `isConnected: False`. In the tray app, the icon shows a red square and the panel says **Can't
    reach Omnilinker.** **Troubleshoot…** shows **No answer** for **omnilinker.pl reachable**.

    1. Test the connection from the agent computer:

       ```powershell theme={null}
       Test-NetConnection omnilinker.pl -Port 443
       ```

       `TcpTestSucceeded : False` means a firewall or the network blocks it. The agent needs outbound HTTPS to
       `omnilinker.pl` on port 443. See [Requirements](/erp/requirements#network).
    2. If your network requires a proxy, set it for the machine with the `HTTPS_PROXY` environment variable, then
       restart the service. The service runs as Local System, so it does not use the proxy settings of the person
       signed in:

       ```powershell theme={null}
       [Environment]::SetEnvironmentVariable("HTTPS_PROXY", "http://<proxy-host>:<port>", "Machine")
       Restart-Service OmnilinkerErpSyncService
       ```
    3. Check which server the agent uses: **Troubleshoot…** names it in the **reachable** check. It should be
       `omnilinker.pl`. To change it, run [setup](/erp/setup-wizard) again and click **Change** next to **Server**.

    While Omnilinker cannot be reached, the agent keeps working from its last downloaded configuration and keeps
    queuing changes. But every failed send counts as an attempt, so a long outage can make queued changes fail for
    good. See **Changes are not arriving**.
  </Accordion>

  <Accordion title="The agent cannot connect to the ERP database">
    The status shows `isErpConnected: False`. In the tray app, the icon shows an amber triangle and the panel says
    **Can't reach the Wapro database.**

    Test the database settings in the tray app: **Test the connection** in the panel, or **Settings…** > **Test
    connection**. **Troubleshoot…** runs the same test and shows SQL Server's message. The test runs inside the
    Windows service, with the service's account, so it behaves the same way as the agent. To change the settings,
    click **Database settings** in the panel, or **Settings…** > **Change…**.

    **The server cannot be found.** SQL Server's message starts with "A network-related or instance-specific error
    occurred while establishing a connection to SQL Server".

    * Check **Server**. For a named instance use `server\instance`, for example `erp-server\WAPRO`.
    * Check that the agent computer can reach the SQL Server port:

      ```powershell theme={null}
      Test-NetConnection <erp-server> -Port 1433
      ```

      Use your instance's port if it is not 1433. A named instance with a dynamic port also needs the SQL Server
      Browser service and UDP port 1434.

    **Login failed.** SQL Server's message starts with "Login failed for user".

    * **SQL Server login**: check the user and password, and that SQL Server allows SQL Server authentication (mixed
      mode).
    * **The service's Windows account**: the agent logs in as the service's account, Local
      System, not as you. The user named in the message is that account: the agent computer's domain account
      (`DOMAIN\COMPUTER$`) on a remote SQL Server, or `NT AUTHORITY\SYSTEM` on SQL Server on the same computer. Give
      that account a login and read access to the ERP database, or use SQL Server authentication. See
      [Requirements](/erp/requirements#sql-server-login).
    * Check that the login can open the database named in **Database**.

    **Certificate errors.** SQL Server's message mentions the certificate, for example "The certificate chain was
    issued by an authority that is not trusted".

    The connection is encrypted when **Encrypt the connection** is ticked, or when SQL Server requires encryption, and
    most SQL Server installations use a self-signed certificate. Either install a certificate on SQL Server that the
    agent computer trusts, or open **Settings…** > **Change…** in the tray app, tick **Trust the server's
    certificate** under **Encryption options** and click **Save**.

    <Note>
      Database settings saved by an earlier version of the tray app left out an unticked **Encrypt**, and the service
      then encrypted anyway. If the test in the database form passes but the service still fails with a certificate
      error, open **Settings…** > **Change…** and save the settings again.
    </Note>
  </Accordion>

  <Accordion title="Changes are not arriving (the outbox is backing up)">
    The agent detects changes but Omnilinker does not receive them. `GET /api/sync/outbox/stats` shows `pending`
    growing, or `failed` above zero. The tray app's panel shows, under **What syncs**, how many changes are waiting
    and how many failed.

    **How the agent retries.** The agent keeps every change in a local outbox and sends it in batches every few
    seconds. When a send fails, for any reason, the change stays **pending** and is tried again in the next cycle.
    After 5 failed attempts (`MaxRetryAttempts` in `appsettings.json`) it is marked **failed** and the agent does not
    send it again.

    Find the reason in the agent's log file. Look for:

    | Log line | Meaning |
    | - | - |
    | `Cloud API returned Unauthorized for batch publish` | The key is rejected. See **The API key is rejected**. |
    | `Cloud API returned Forbidden for batch publish:` | The text after it says why: an agent that is too old, an inactive connection, or a key for another connection. |
    | `Failed to publish chunk` | The send failed, often because Omnilinker could not be reached. See **The agent cannot reach omnilinker.pl**. |
    | `OUTBOX PARTIAL REJECTION` | Omnilinker accepted some changes and rejected others. The line lists the first reasons. |

    Also check that the connection is **Active** in Omnilinker.

    Changes that have already failed every attempt are not sent again automatically. A later change to the same
    record in the ERP is detected and sent as usual. To send the failed changes again after a fix, open **Sync
    details…** > **Activity** in the tray app and click **Try again now**. See
    [Sync details](/erp/tray-app#sync-details).
  </Accordion>

  <Accordion title="The agent is online but nothing syncs">
    The **Agent** tab says **Online**, but no new sync log entries appear in Omnilinker.

    Check, in order:

    1. **Is syncing paused?** The tray icon shows a grey circle with a pause sign and the tooltip says **Paused**, or
       the status shows `state: 2`. Select **Resume sync** in the tray app's panel or menu. See
       [Tray app](/erp/tray-app#sync-now-check-everything-pause).
    2. **Is the entity type configured?** On the connection's **Sync Configuration** tab, each entity type you want
       to sync needs a configuration that is **Enabled**. If the tab says "No sync configurations found. Add one to
       enable synchronization.", add one. See [Sync configuration](/erp/sync-configuration).
    3. **Is change detection on?** With hash scan change detection (the default), the agent finds changes only with
       hash checks. Open the **Product** sync configuration, expand **Advanced Timing Settings** and make sure
       **Hash-Based Change Detection** is **Enabled**. The tray app's **Sync details…** shows when the last **Full
       check** ran.
    4. **Has the agent loaded its configuration?** If `lastError` is `Waiting for cloud configuration`, the agent has
       not yet downloaded its settings from Omnilinker. See **The API key is rejected** and **The agent cannot reach
       omnilinker.pl**.
    5. **Are the ERP database settings set?** If `lastError` is `ERP credentials not configured`, or the tray app's
       panel shows the database as **Not set**, finish the database step of [setup](/erp/setup-wizard): **Database
       settings** in the panel, or **Settings…** > **Change…**.
    6. **Has anything changed in the ERP?** The agent sends only changes. The first full check after installation
       compares every record; later ones find only what changed since. To check now, click **Check everything** in
       the tray app's panel.

    A full check runs on its interval (15 minutes by default). **Sync now** in the tray app starts one sooner.
  </Accordion>

  <Accordion title="Changes arrive as Skipped">
    Sync log entries in Omnilinker show no status badge, and their error message is a code such as
    `ErpIntegration:Skip:ProductNotMapped`. Omnilinker received the change but did not apply it on purpose.

    Most of these mean something is not mapped yet:

    * `ErpIntegration:Skip:PriceLevelNotMapped` or `ErpIntegration:Skip:WarehouseNotMapped`: map the ERP price level
      or warehouse on the connection's **Mappings** tab. See [Reference items](/erp/reference-items).
    * `ErpIntegration:Skip:ProductNotMapped`: the price, stock or bundle belongs to a product that is not linked to a
      catalog product yet. Make sure products sync first. See [Field mappings](/erp/field-mappings).

    The full list is in [Monitoring](/erp/monitoring#sync-logs).
  </Accordion>

  <Accordion title="Test Connection in the web app always fails">
    **Test Connection** in a connection's **Actions** menu always reports a failure. That is expected: Omnilinker
    does not have your ERP database credentials, which stay on the agent computer. Test the database connection in
    the tray app instead: **Settings…** > **Test connection**.
  </Accordion>

  <Accordion title="Trigger Sync or Retry in the web app does nothing">
    **Trigger Sync** on the connection page (and the sync button on the dashboard) confirms "Synchronization has been
    triggered", but it does not reach the agent. **Retry** on a failed sync log entry only sets it back to
    **Pending**.

    To make the agent look for changes now, use **Sync now** or **Check everything** in the tray app, or
    `POST /api/sync/now` on the [local API](/erp/local-api). See also [Monitoring](/erp/monitoring).
  </Accordion>

  <Accordion title="The Local Service tab says Local Sync Service Not Available">
    The **Local Service** tab of a connection talks to the agent at `http://localhost:5555` from your browser. It
    works only in a browser on the agent computer, with the agent on port 5555. On any other computer this message
    is expected. Use the **Agent** tab instead. See [Monitoring](/erp/monitoring#local-service-tab).
  </Accordion>
</AccordionGroup>

## Get help

If none of this solves the problem, contact Omnilinker support.

Include:

* The connection name, and what you see on its **Agent** tab.
* The agent's version, from the **Agent** tab or the `version` field of `GET /api/sync/status`.
* The output of the quick checks at the top of this page.
* The service log files from the time the problem started.

<Warning>
  Never send `credentials.dat`, and do not paste your API key or ERP password into a message. The local API never
  returns them. Look through the log files before you send them.
</Warning>
