i'm doing custom checkout with my module, this module create 2 input in first step (shipping address step) and this first step is working fine, but in the 2nd step, it throw error with status code 500, lets take a look at the description image below :
First step: enter image description here

First step working fine with status code 200 and sending extension attribute. enter image description here

But in the second step, when i click at "Place Order", it return status code 500 with this error message: enter image description here

So here is my code:


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Quote\Model\ShippingAddressManagement">
        <plugin name="custom_quote_delivery" type="Aht\MagentoCheckoutCustom\Plugin\Quote\Model\ShippingAddressManagement" sortOrder="1" disabled="false"/>


<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\AddressInterface">
        <attribute code="delivery_instruction" type="string"/>
        <attribute code="delivery_type" type="string"/>


namespace Aht\MagentoCheckoutCustom\Plugin\Quote\Model;

class ShippingAddressManagement
    protected $logger;

    public function __construct(
        \Psr\Log\LoggerInterface $logger
    ) {
        $this->logger = $logger;

    public function beforeAssign(
        \Magento\Quote\Model\ShippingAddressManagement $subject,
        \Magento\Quote\Api\Data\AddressInterface $address
    ) {
//        try {
            $extAttributes = $address->getExtensionAttributes();

            $deliveryInstruction = $extAttributes->getDeliveryInstruction();
            $deliveryType = $extAttributes->getDeliveryType();
//        } catch (\Exception $e) {
//            $this->logger->critical($e->getMessage());
//        }


namespace Aht\MagentoCheckoutCustom\Setup;

use Magento\Framework\Setup\UpgradeSchemaInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\DB\Ddl\Table;

class UpgradeSchema implements UpgradeSchemaInterface
    public function upgrade(SchemaSetupInterface $setup, ModuleContextInterface $context)
        $installer = $setup;


        if (version_compare($context->getVersion(), '1.1.0', '<')) {
            if ($installer->tableExists('quote')) {
                $connection = $installer->getConnection();
                $tableName = $installer->getTable('quote');

                            'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                            'nullable' => false,
                            'comment' => 'Delivery Instruction'
                            'type' => \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
                            'nullable' => false,
                            'comment' => 'Delivery Type'



 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.

var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/action/set-shipping-information': {
                'Aht_MagentoCheckoutCustom/js/action/set-shipping-information': true


], function ($, wrapper, quote) {
    'use strict';

    return function (setShippingInformationAction) {

        return wrapper.wrap(setShippingInformationAction, function (originalAction) {
            var shippingAddress = quote.shippingAddress();
            if (shippingAddress['extension_attributes'] === undefined) {
                shippingAddress['extension_attributes'] = {};

            shippingAddress['extension_attributes']['delivery_instruction'] = $('[name="delivery_instruction"]').val();
            shippingAddress['extension_attributes']['delivery_type'] = $('[name="delivery_type"]').val();
            // pass execution to original action ('Magento_Checkout/js/action/set-shipping-information')
            return originalAction();

Ok, so i've success created 2 column in "Quote" table named "delivery_instruction" and "delivery_type".
And i've follow a lot of source and topic (devdoc, stackexchange, github) but i thing i saw 2 ways to do this.. the sohelrana09 way on github is using another way as what i did.
Here is sohelrana09 way:
And the way i'm following to is from here and the devdoc:
Save a custom attribute from shipping method to quote_address
I've also found another way convert 2 way somehow .. but doesn't have example
Save Custom field in shipping address at Checkout in Magento 2

Okay so i dont know which one is correct, and if both correct, which one is better, Thanks for reading, Have a good day :)

1 Answer 1


That means your code at line:

$extAttributes = $address->getExtensionAttributes(); //return null

please use a plugin to before save instead or add a new observer to the event sales_quote_address_save_before

Example Event observer:

<event name="sales_quote_address_save_before">
    <observer name="namespace_module_addres_save_before" instance="Namespace\Module\Observer\AddressDataBeforeSave" />

use Magento\Framework\Event\ObserverInterface;

class AddressDataBeforeSave implements ObserverInterface
     *          *
     * @param \Magento\Framework\Event\Observer $observer
     * @return $this
    public function execute(\Magento\Framework\Event\Observer $observer)
        $quoteAddress = $observer->getEvent()->getQuoteAddress();
        //enter code here
        return $this;
  • Oh thanks.. i'll do it and feedback to you later :)
    – fudu
    Commented Sep 15, 2018 at 10:07
  • Hi .. about ur answer, do you mean i need to follow this source? github.com/sohelrana09/magento2-module-delivery-date/tree/… because i see it really look like your answer, and if i follow this source, should i remove mine?
    – fudu
    Commented Sep 15, 2018 at 15:24
  • Right now, i'm not using observer, and i'm override this Magento\Quote\Model\ShippingAddressManagement, but in that source, they use observer and override Magento\Checkout\Model\ShippingInformationManagement instead
    – fudu
    Commented Sep 15, 2018 at 15:28
  • Dont mater what source did you tried. In your case that mean extAttr doesn't process yet beforeSave to make sure extAttr has processed.
    – HoangHieu
    Commented Sep 15, 2018 at 15:34
  • Sorry i'm new with this, first time know about observer and plugin ..
    – fudu
    Commented Sep 15, 2018 at 15:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.