Dear colleagues, I've prepared a fix for the problem, which works _for me_ but this is rather suggestion than fix, which requires your review and can be the first step to general fix. So, creation of object is ok because there is check for 'None' parameters before sending them to Neutron: port.py/handle_create() calls neutron.py/prepare_properties() which in turn validates key-value pairs: props = dict((k, v) for k, v in properties.items() if v is not None) while, for example, port.py/handle_update() doesn't. I've changed two files: ===== port.py ===== $ diff -u port.py.orig port.py --- port.py.orig 2017-04-21 08:55:19.033207478 +0000 +++ port.py 2017-04-21 08:59:29.259608748 +0000 @@ -519,8 +519,11 @@ prop_diff['qos_policy_id'] = self.client_plugin( ).get_qos_policy_id(qos_policy) if qos_policy else None self._prepare_port_properties(prop_diff, prepare_for_update=True) - LOG.debug('updating port with %s' % prop_diff) - self.client().update_port(self.resource_id, {'port': prop_diff}) + #-- doka -- https://bugs.launchpad.net/bugs/1681769 + prop_diff_cleaned = dict((k, v) for k, v in prop_diff.items() + if v is not None) + LOG.debug('updating port with %s' % prop_diff_cleaned) + self.client().update_port(self.resource_id, {'port': prop_diff_cleaned}) def check_update_complete(self, *args): attributes = self._show_resource() ===== security_group.py ===== # diff -u security_group.py.orig security_group.py --- security_group.py.orig 2017-04-21 09:08:52.492005906 +0000 +++ security_group.py 2017-04-21 10:11:53.083743117 +0000 @@ -11,6 +11,8 @@ # License for the specific language governing permissions and limitations # under the License. +from oslo_log import log as logging + from heat.common import exception from heat.common.i18n import _ from heat.engine import constraints @@ -18,6 +20,8 @@ from heat.engine.resources.openstack.neutron import neutron from heat.engine import support +LOG = logging.getLogger(__name__) + class SecurityGroup(neutron.NeutronResource): """A resource for managing Neutron security groups. @@ -254,8 +258,12 @@ if prop_diff: self.prepare_update_properties(prop_diff) + #-- doka -- https://bugs.launchpad.net/bugs/1681769 + prop_diff_cleaned = dict((k, v) for k, v in prop_diff.items() + if v is not None) + LOG.debug('updating security group with %s' % prop_diff_cleaned) self.client().update_security_group( - self.resource_id, {'security_group': prop_diff}) + self.resource_id, {'security_group': prop_diff_cleaned}) if rules: self._create_rules(rules) This change removes empty (None) keys from dictionary before it passed to Neutron and latter accepts this update. Probably, there are other places in Heat where such validation is required and that's why I don't see it as a final fix, but rather informational message on how this problem can be solved. Thank you.