# Buggy code
def build_default_node(inp: bpy.types.NodeSocket):
    """Creates a new node to give a not connected input socket a value"""

    is_custom_socket = isinstance(inp, arm.logicnode.arm_sockets.ArmCustomSocket)

    if is_custom_socket:
        # ArmCustomSockets need to implement get_default_value()
        default_value = inp.get_default_value()
        if isinstance(default_value, str):
            default_value = '"{:s}"'.format(default_value.replace('"', '\\"'))
        inp_type = inp.arm_socket_type  # any custom socket's `type` is "VALUE". might as well have valuable type information for custom nodes as well.
    else:
        default_value = inp.default_value
        if isinstance(default_value, str):
            default_value = '"{:s}"'.format(default_value.replace('"', '\\"'))
        inp_type = inp.type

    # Don't write 'None' into the Haxe code
    if default_value is None:
        default_value = "null"

    if inp_type == "VECTOR":
        return f"new armory.logicnode.VectorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})"
    elif inp_type == "RGBA":
        return f"new armory.logicnode.ColorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]}, {default_value[3]})"
    elif inp_type == "RGB":
        return f"new armory.logicnode.ColorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})"
    elif inp_type == "VALUE":
        return f"new armory.logicnode.FloatNode(this, {default_value})"
    elif inp_type == "INT":
        return f"new armory.logicnode.IntegerNode(this, {default_value})"
    elif inp_type == "BOOLEAN":
        return f"new armory.logicnode.BooleanNode(this, {str(default_value).lower()})"
    elif inp_type == "STRING":
        return f"new armory.logicnode.StringNode(this, {default_value})"
    elif inp_type == "NONE":
        return "new armory.logicnode.NullNode(this)"
    elif inp_type == "OBJECT":
        return f"new armory.logicnode.ObjectNode(this, {default_value})"
    elif is_custom_socket:
        return f"new armory.logicnode.DynamicNode(this, {default_value})"
    else:
        return "new armory.logicnode.NullNode(this)"


# Traceback (AttributeError)
Error: Traceback (most recent call last):
File "D:\Armory\ArmorySDK//armory/blender\arm\props_ui.py", line 543, in execute
make.play()
File "D:\Armory\ArmorySDK//armory/blender\arm\make.py", line 482, in play
build(target=runtime_to_target(), is_play=True)
File "D:\Armory\ArmorySDK//armory/blender\arm\make.py", line 370, in build
export_data(fp, sdk_path)
File "D:\Armory\ArmorySDK//armory/blender\arm\make.py", line 94, in export_data
make_logic.build()
File "D:\Armory\ArmorySDK//armory/blender\arm\make_logic.py", line 32, in build
build_node_tree(tree)
File "D:\Armory\ArmorySDK//armory/blender\arm\make_logic.py", line 80, in build_node_tree
build_node(node, f)
File "D:\Armory\ArmorySDK//armory/blender\arm\make_logic.py", line 184, in build_node
inp_name = build_default_node(inp)
File "D:\Armory\ArmorySDK//armory/blender\arm\make_logic.py", line 259, in build_default_node
default_value = inp.default_value
AttributeError: 'NodeSocketShader' object has no attribute 'default_value'

# Fixed code
def build_default_node(inp: bpy.types.NodeSocket):
    """Creates a new node to give a not connected input socket a value"""

    is_custom_socket = isinstance(inp, arm.logicnode.arm_sockets.ArmCustomSocket)

    if is_custom_socket:
        # ArmCustomSockets need to implement get_default_value()
        default_value = inp.get_default_value()
        if isinstance(default_value, str):
            default_value = '"{:s}"'.format(default_value.replace('"', '\\"'))
        inp_type = inp.arm_socket_type  # any custom socket's `type` is "VALUE". might as well have valuable type information for custom nodes as well.
    else:
        if hasattr(inp, "default_value"):
            default_value = inp.default_value
        else:
            default_value = None
        if isinstance(default_value, str):
            default_value = '"{:s}"'.format(default_value.replace('"', '\\"'))
        inp_type = inp.type

    # Don't write 'None' into the Haxe code
    if default_value is None:
        default_value = "null"

    if inp_type == "VECTOR":
        return f"new armory.logicnode.VectorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})"
    elif inp_type == "RGBA":
        return f"new armory.logicnode.ColorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]}, {default_value[3]})"
    elif inp_type == "RGB":
        return f"new armory.logicnode.ColorNode(this, {default_value[0]}, {default_value[1]}, {default_value[2]})"
    elif inp_type == "VALUE":
        return f"new armory.logicnode.FloatNode(this, {default_value})"
    elif inp_type == "INT":
        return f"new armory.logicnode.IntegerNode(this, {default_value})"
    elif inp_type == "BOOLEAN":
        return f"new armory.logicnode.BooleanNode(this, {str(default_value).lower()})"
    elif inp_type == "STRING":
        return f"new armory.logicnode.StringNode(this, {default_value})"
    elif inp_type == "NONE":
        return "new armory.logicnode.NullNode(this)"
    elif inp_type == "OBJECT":
        return f"new armory.logicnode.ObjectNode(this, {default_value})"
    elif is_custom_socket:
        return f"new armory.logicnode.DynamicNode(this, {default_value})"
    else:
        return "new armory.logicnode.NullNode(this)"