REST errors and troubleshooting
When a REST call fails, Epicor returns an HTTP status code and a JSON body describing the problem. This page explains how to read that body and what the common codes usually mean.
The error body
Section titled “The error body”Errors look like this (XML instead if the request’s Accept header asks for application/xml):
{ "HttpStatus": 400, "ReasonPhrase": "REST Api Exception", "ErrorMessage": "Part is required.", "ErrorType": "Ice.Common.BusinessObjectException", "ErrorDetails": [ { "Message": "Part is required.", "Type": "Error", "Table": "OrderDtl" } ]}ErrorMessageis the text to log and, often, to show a user.ErrorTypetells you which layer rejected the call.Epicor.RESTApi.ErrorHandling.ApiExceptionmeans the REST layer itself (bad URL, unknown service);Ice.Common.BusinessObjectExceptionmeans Epicor’s business logic (or a BPM) refused the data.ErrorDetailslists each problem, sometimes with the table and row. Update calls that fail on several rows return one entry per row.
Log the whole body in your integration, not just the status code.
Status codes and usual causes
Section titled “Status codes and usual causes”| Status | Typical ErrorType |
Usual cause |
|---|---|---|
| 400 Bad Request | BusinessObjectException, BLException |
Business logic rejected the data: a required field is missing, a value is invalid, or a BPM raised an exception. Read ErrorMessage. |
| 400 Bad Request | ODataException |
The OData query is malformed: a misspelt field in $filter, wrong quoting, or wrong case. |
| 400 Bad Request | BusinessObjectException from a BAQ |
An updatable BAQ’s update failed; details list the rows. |
| 401 Unauthorized | Missing or wrong credentials, or an expired token. | |
| 403 Forbidden | UnauthorizedAccessException |
The user or API key isn’t allowed to use the service or method: menu/service security or the key’s access scope. |
| 404 Not Found | ApiException, RecordNotFoundException |
Wrong service or entity name (check case), a record that doesn’t exist, or an Epicor Function that’s unpublished, disabled or not mapped to the company. |
| 409 Conflict | DuplicateRecordException |
Adding a record whose key already exists. |
| 410 Gone | InvalidSessionException |
A session ID sent in a SessionInfo header has timed out. Log in again. |
| 500 Internal Server Error | various | An unexpected server error. Details are hidden from remote callers by default. |
| 503 Service Unavailable | ConversionsPendingException and others |
The server isn’t ready, for example after an upgrade with conversions still pending. |
Common problems
Section titled “Common problems”Every v2 call is rejected, but the login is right
Section titled “Every v2 call is rejected, but the login is right”The request has no x-api-key header or api-key parameter, the key was generated in a different
environment, it has expired, or it’s disabled. Generate a key in the environment you’re calling. See
Authentication, API keys and integration accounts.
It works in the help page but not from code
Section titled “It works in the help page but not from code”Compare the request in the help page’s curl output with what your code sends. The usual differences
are the company in the URL, a missing Content-Type: application/json header on a POST, parameter
name case, and GET versus POST for the method.
403 even though the user can do it on screen
Section titled “403 even though the user can do it on screen”The API key’s access scope doesn’t include the service, method, BAQ or function. Add it to the scope, or test with a key that has no scope to confirm that’s the cause.
Epicor Function returns 404
Section titled “Epicor Function returns 404”See Troubleshooting functions:
company mapping, disabled, unpublished without the staging URL, or internal-only.
A save works in the screen but fails over REST
Section titled “A save works in the screen but fails over REST”The screen calls Change… methods before saving that fill in dependent fields; your call went
straight to Update (or used an OData POST/PATCH). Replay the screen’s method sequence; see
Call Epicor from another application.
A BPM directive can also be the difference: directives that show a BPM data form or ask a question can’t be answered by an integration. Make them skip for your integration account.
Results stop at 100 rows
Section titled “Results stop at 100 rows”That’s the default row limit. Page with $top and $skip; see
Call Epicor from another application.
Seeing more detail
Section titled “Seeing more detail”- Browser DevTools. To see how a screen makes the call you’re trying to copy, open DevTools (F12 in Chrome and Edge, Ctrl+Shift+I in Firefox) and watch the Network tab while you work in Kinetic. Each request shows the URL, method, headers and JSON body.
- Full error text (on-premises). Remote callers get a generic message for server errors unless an
administrator sets
SecureErrorstofalsein the server’shost.config. Only do that in test environments. - REST tracing (on-premises). Adding the
trace://ice/fw/restapiflag toAppServer.configwrites REST call processing to the server log;trace://ice/fw/servicecalleradds which service each call loaded.