Magento 1.9 – Fixing ‘Invalid Carrier Specified’ Error When Adding Tracking to Shipment

apimagento-1.9modulePHPsoap

I'm trying to add tracking to orders via the SOAP (V1) interface using the sales_order_shipment.addTrack method – but as the title suggests I'm getting the following error: Invalid carrier specified

The first thing I tried was to use the custom carrier code as such:

'shipmentIncrementId' => $shipmentIncrementId,
'carrier' => 'custom',
'title' => 'My courier',
'trackNumber' => $tracking

(Note that both $shipmentIncrementId and $tracking are correct.)

This produced the aforementioned error.

So I decided to make my own module adding a custom carrier, I followed this tutorial. Most importantly, I've implemented isTrackingAvailable() and made it return true.

Now, interestingly, if I make the call to sales_order_shipment.getCarriers my custom carrier is there, so it should be available! However, when I again make the sales_order_shipment.addTrack call with the following details:

'shipmentIncrementId' => $shipmentIncrementId,
'carrier' => 'name_of_module',
'title' => 'Custom Carrier',
'trackNumber' => $tracking

Where name_of_module is obviously the correct name of the module, returned by getCarriers and this time I've matched the title to the one defined in the module (Custom Carrier).

With this, I still get the same error of Invalid carrier specified! Surely if getCarriers returns this carrier for an order it shouldn't be invalid?

The only place on the web that attempts to document this error is here, as described above I have followed the suggested steps according to that link.

Could anyone point me to where I'm going wrong? Thanks in advance for your help.

P.S. If it makes any difference, I'm trying to avoid adding a new module for every single carrier we use, I'd like to be able to pass through the correct title of the carrier through SOAP and add any tracking number (we don't use any of the predefined carriers in Magento).


Edit

The following is the code that calls the API:

$this->magentoAPI->request(
    'sales_order_shipment.addTrack',
        [
            'shipmentIncrementId' => $shipmentIncrementId,
            'carrier' => 'fesp_fixstupidcarriers',
            'title' => 'Custom Carrier',
            'trackNumber' => $tracking,
        ]
);

This uses my custom function, which in turn runs call_user_func_array([$client, 'call'], $arguments);

$arguments comes out as the following array:

[
    'whatever-the-session-id-is',
    'sales_order_shipment.addTrack',
    '100002290',
    'fesp_fixstupidcarriers',
    'Custom Carrier',
    '9348278247008183'
];

I'm showing actual data this time, that's a real shipmentIncrementId, the actual carrier code, and the real tracking number.

This function works for all other calls of the API I've tried (about a dozen).

Best Answer

I'm not sure what can cause this but I'm going to give you the steps to debug the problem.

The error

The error you're getting:

Invalid carrier specified.

Comes from the following file: app/code/core/Mage/Sales/Model/Order/Shipment/Api.php in the addTrack() method:

public function addTrack($shipmentIncrementId, $carrier, $title, $trackNumber)
{
    $shipment = Mage::getModel('sales/order_shipment')->loadByIncrementId($shipmentIncrementId);

    /* @var $shipment Mage_Sales_Model_Order_Shipment */

    if (!$shipment->getId()) {
        $this->_fault('not_exists');
    }

    $carriers = $this->_getCarriers($shipment);

    if (!isset($carriers[$carrier])) {
        $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));
    }

    $track = Mage::getModel('sales/order_shipment_track')
                ->setNumber($trackNumber)
                ->setCarrierCode($carrier)
                ->setTitle($title);

    $shipment->addTrack($track);

    try {
        $shipment->save();
        $track->save();
    } catch (Mage_Core_Exception $e) {
        $this->_fault('data_invalid', $e->getMessage());
    }

    return $track->getId();
}

As you can see this method does the following:

  • load the shipment
  • get the carriers for the shipment
  • check if the carrier provided is allowed
  • create the tracking
  • add the tracking to the shipment
  • save both tracking and shipment

Investigating

As you can see, the list of allowed carriers is retrieved via a protected method in that same class _getCarriers :

protected function _getCarriers($object)
{
    $carriers = array();
    $carrierInstances = Mage::getSingleton('shipping/config')->getAllCarriers(
        $object->getStoreId()
    );

    $carriers['custom'] = Mage::helper('sales')->__('Custom Value');
    foreach ($carrierInstances as $code => $carrier) {
        if ($carrier->isTrackingAvailable()) {
            $carriers[$code] = $carrier->getConfigData('title');
        }
    }

    return $carriers;
}

Here how I would start the debugging process.

  1. Add the following line at the beggining of the addTrack() method:

    Mage::log("---".$carrier."---");
    
  2. Then add the following line before return $carriers; in the _getCarriers() method:

    Mage::log($carriers);
    
  3. Call your sales_order_shipment.addTrack and check your var/log/system.log for the result

Case 1: your carrier code is not a key of the carriers array

Two possibilities here:

  • Your carrier is not enabled / allowed for the specified store. Indeed the following code retrieves the list of all carriers but it filters them by store id. Double check the carrier configuration using the scope dropdown:

    $carrierInstances = Mage::getSingleton('shipping/config')->getAllCarriers(
        $object->getStoreId()
    );
    
  • Your carrier does not have tracking available. I guess you already did check that but open the model that corresponds to the carrier and check what the isTrackingAvailable() method returns. If such method is not declared in the carrier model, that means it returns false and thus tracking is not available for this carrier.

Case 2: your carrier code is a key of the carrier array

First, ensure that there's no whitespaces around your carrier code. That's the reason why I added the --- before and after the carrier code in the debugging code.

You can further investigate the differences by replacing:

    if (!isset($carriers[$carrier])) {
        $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));
    }

By:

foreach ($carriers as $key => $value) {
    Mage::log("checking key: ".$key."---");
    Mage::log("provided key: ".$carrier."---");
}
if (!isset($carriers[$carrier])) {
    $this->_fault('data_invalid', Mage::helper('sales')->__('Invalid carrier specified.'));
}

If you're in this case, it's pretty much a typo IMO.

Related Topic