Status Codes & Errors

HTTP Status Codes

The OnSite API uses conventional HTTP response codes to indicate the success or failure of an API request.

Status Code Message
200
OK. The request has succeeded.
201
Created. The request has been fulfilled and a new resource was created.
400
Bad Request. The request could not be understood by the server. This can
occur if:
* The syntax of the XML object is incorrect
* The XML object contains read-only information
* The XML object is being written to the wrong URL
401
Unauthorized. The request requires user authentication. May occur if
one or more of the following are missing or incorrect in the request
object:
* App ID (in the User-Agent header)
* Private ID (in the X-PAPPID header)
* Lightspeed username or password (in the Authorization header)
Or if the API Application is not licensed to the server (see
403
Forbidden. The server understood the request, but is refusing to fulfill
it. May occur if there are no more user-seats available to connect to the
LightSpeed Server (see the note in Authentication); if you
attempt a POST/PUT/UNLOCK/LOCK call using a read-only application; or the
url is malformed.
404
Not Found. The server has not found anything matching the URL.
405
Method Not Allowed. Normally occurs when attempting a POST/PUT/UNLOCK/LOCK
on a resource that doesn’t support it.
406
Not Acceptable. Normally occurs when there’s something incorrect about the
request, for instance, when attempting a PUT request on an Invoice whose
Posted flag is set to TRUE (you cannot edit a posted invoice. It must be
unposted first).
500
Internal Server Error. Something went wrong with the OnSite API.

Error Response

Errors with the OnSite API are accompanied by an XML object documenting what went wrong.

<error class="lscore.errors.lightspeed_errors.ExampleError" type="server.lightspeederror">
  <localizable_message type="server.example_error">
    <fields>
      <field name="some_property">4</field>
      <field name="some_other_property">bar</field>
    </fields>
    <plain_message>This is an example error message.</plain_message>
  </localizable_message>
  <traceback/>
</error>

When parsing, the class attribute in the root error element is the identifier for the error, and the plain_message contains the human-readable string explaining the error. The traceback is for debugging purposes by the OnSite API developers.

The localizable message’s type and fields can be utilized by the developer to localize or make custom error messages. For localization, the plain_message contains the English-language string associated with the type to translate. The field elements have the attribute name that identify the information contained inside the element.

Authentication Errors

There are three headers in a request for authenticating. The Private ID is included in the X-PAPPID header, the App ID is included in the User-Agent header, and the Lightspeed username and password are encoded in the Authorization header.

When the X-PAPPID or User-Agent header are incorrect, because the App ID or Private ID are incorrect, the following response is generated:

<error class="lsserver.auth.auth_service.InvalidUserAgent" type="auth.invalid_user_agent">
  <localizable_message type="auth.unsupported_client_version">
    <fields/>
    <plain_message>Unsupported client version. Please upgrade you client install.</plain_message>
  </localizable_message>
  <traceback/>
</error>

When the Lightspeed username or password is incorrect, the following response is returned:

<error class="lscore.errors.server_errors.Unauthorized" type="server.unauthorized">
  <localizable_message type="server.unauthorized">
    <fields>
      <field name="message">None</field>
    </fields>
    <plain_message>Unauthorized Request: None</plain_message>
  </localizable_message>
  <traceback/>
</error>

Validation Errors

When requests include a POST or PUT payload, the contents of that payload is first passed by a validator. At first there’s a check to see that the XML is valid. If it is not, an error akin to the following might be produced:

<error class="lscore.errors.lightspeed_errors.LightSpeedError" type="server.lightspeederror">
  <localizable_message type="server.lightspeederror">
    <fields/>
    <plain_message>An unexpected error occurred.</plain_message>
  </localizable_message>
  <traceback>Traceback (most recent call last):
  File "core/src/lscore/rest/request_handling.py", line 743, in new_f
    res = callable(self, *args, **kwargs)
  File "core/src/lscore/rest/request_handling.py", line 677, in new_f
    response = callable(self, *new_args, **new_kwargs)
  File "core/src/lscore/rest/framework.py", line 583, in post
    return create(request, response, False, **kwargs)
  File "core/src/lscore/rest/framework.py", line 551, in create
    resource_data.root = creator.validate_create(resource_data)
  File "source/src/lsserver/rest/standard_impl.py", line 203, in validate_create
    return resource_data.request.request_as_xml(self.__validation_schema)
  File "core/src/lscore/rest/request_handling.py", line 167, in request_as_xml
    root = etree.fromstring(payload_xml)
  File "lxml.etree.pyx", line 3032, in lxml.etree.fromstring (src/lxml/lxml.etree.c:68121)
  File "parser.pxi", line 1786, in lxml.etree._parseMemoryDocument (src/lxml/lxml.etree.c:102470)
  File "parser.pxi", line 1674, in lxml.etree._parseDoc (src/lxml/lxml.etree.c:101299)
  File "parser.pxi", line 1074, in lxml.etree._BaseParser._parseDoc (src/lxml/lxml.etree.c:96481)
  File "parser.pxi", line 582, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:91290)
  File "parser.pxi", line 683, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:92476)
  File "parser.pxi", line 622, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:91772)
XMLSyntaxError: AttValue: " or ' expected, line 2, column 14
</traceback>
</error>

Then the validator checks to see that all the fields are properly entered. If this fails due to a missing element or whatnot, the OnSite API can spit out an error akin to the following:

<error class="lscore.rest.request_handling.ValidationError" type="resource.validation_error">
  <localizable_message type="resource.validation_error">
    <fields>
      <field name="error_message">Expecting an element product, got nothing, line 1

&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_NOELEM: Expecting an element product, got nothing
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_INTERSEQ: Invalid sequence in interleave
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_CONTENTVALID: Element gift_card failed to validate content</field>
    </fields>
    <plain_message>Unable to validate xml:
Expecting an element product, got nothing, line 1

&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_NOELEM: Expecting an element product, got nothing
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_INTERSEQ: Invalid sequence in interleave
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_CONTENTVALID: Element gift_card failed to
validate content</plain_message>
  </localizable_message>
  <traceback>Traceback (most recent call last):
  File "core/src/lscore/rest/request_handling.py", line 743, in new_f
    res = callable(self, *args, **kwargs)
  File "core/src/lscore/rest/request_handling.py", line 677, in new_f
    response = callable(self, *new_args, **new_kwargs)
  File "core/src/lscore/rest/framework.py", line 583, in post
    return create(request, response, False, **kwargs)
  File "core/src/lscore/rest/framework.py", line 551, in create
    resource_data.root = creator.validate_create(resource_data)
  File "source/src/lsserver/rest/standard_impl.py", line 203, in validate_create
    return resource_data.request.request_as_xml(self.__validation_schema)
  File "core/src/lscore/rest/request_handling.py", line 169, in request_as_xml
    _Validator.validate(schema, root)
  File "core/src/lscore/rest/request_handling.py", line 88, in validate
    self.raise_rng_error(error)
  File "core/src/lscore/rest/request_handling.py", line 114, in raise_rng_error
    raise ValidationError(str(rng_error) + '\n\n' + str(rng_error.error_log))
ValidationError: Unable to validate xml:
Expecting an element product, got nothing, line 1

&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_NOELEM: Expecting an element product, got nothing
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_INTERSEQ: Invalid sequence in interleave
&lt;string&gt;:1:0:ERROR:RELAXNGV:RELAXNG_ERR_CONTENTVALID: Element gift_card failed to validate content
</traceback>
</error>

Locked Resource Error

Resources in the Onsite API can be locked, preventing other users from updating resources at the same time. See Locking & Unlocking Resources for more information. If you send a request that requires a lock, but do not do so, the following error may occur:

<error class="lscore.locking.errors.NotLockedError" type="resource.not_locked">
  <localizable_message type="resource.not_locked">
    <fields>
      <field name="item_id">67</field>
      <field name="lock_name">product</field>
    </fields>
    <plain_message>Acquire a lock on product with id 67 first</plain_message>
  </localizable_message>
  <traceback>Traceback (most recent call last):
  File "core/src/lscore/rest/request_handling.py", line 743, in new_f
    res = callable(self, *args, **kwargs)
  File "core/src/lscore/rest/request_handling.py", line 677, in new_f
    response = callable(self, *new_args, **new_kwargs)
  File "core/src/lscore/rest/framework.py", line 583, in post
    return create(request, response, False, **kwargs)
  File "core/src/lscore/rest/framework.py", line 550, in create
    with self.lock_gen( resource_data, creator.get_lockable(resource_data) ):
  File "/lib/python2.7/contextlib.py", line 17, in __enter__
    return self.gen.next()
  File "core/src/lscore/rest/framework.py", line 183, in lock_gen
    raise NotLockedError(lockable.name, lockable.id)
NotLockedError: Acquire a lock on product with id 67 first
</traceback>
</error>

When attempting to use a resource that’s already locked, an error like the following may occur:

<error class="lscore.locking.errors.NotYourLockError" type="resource.not_your_lock">
  <localizable_message type="resource.not_your_lock">
    <fields>
      <field name="item_id">68</field>
      <field name="lock_name">product</field>
      <field name="current_lock_holder">lightspeed</field>
    </fields>
    <plain_message>product is in use by lightspeed. You will not be able to make changes until
    lightspeed closes the document.</plain_message>
  </localizable_message>
  <traceback>Traceback (most recent call last):
  File "core/src/lscore/rest/request_handling.py", line 695, in new_f
    res = callable(self, request, response, *args, **kwargs)
  File "core/src/lscore/rest/framework.py", line 780, in PUT
    return self.update(request, response, True, *args)
  File "core/src/lscore/rest/framework.py", line 768, in update
    with self.lock_gen( resource_data, updater.get_lockable(resource_data) ):
  File "/lib/python2.7/contextlib.py", line 17, in __enter__
    return self.gen.next()
  File "core/src/lscore/rest/framework.py", line 187, in lock_gen
    lock.current_lock_holder.username)
NotYourLockError: product is in use by lightspeed.
You will not be able to make changes until lightspeed closes the document.
</traceback>
</error>

Note

This error can also occur if you locked the resource, but did not do the PUT request as part of the same session.

Other Errors

When the connection to the OnSite API fails without producing an error generated by the API, there are other things to watch for when debugging:

  • An incompatible version of LightSpeed Server (Demo, 3.4.5 or lower)
  • SSL certificate verification not disabled
  • Incorrect Port number (should only be 9630 or 9631 in some cases, anything else will trigger the error)
  • Blocked port (9630, 9631 are the ports that LightSpeed Server will use)
  • Issue with IP address in URL (does not exist, blocked, etc)
  • Attempt to acquire a substantially vast amount of data (ex. GET /api/products/ of a database with over 15K products)