When you run a script from the Text Editor you use its `bpy.context`. The Text Editor does not have any node trees you have to call in the right context. To use the context of an editor which API you use, you can create a button in that editor to run your script. Or, as it was suggested, [to pass a context][1] to an API function as an argument. You cannot make it simpler with a context-dependent API. [![enter image description here][2]][2] Your code should be in that `def execute()` function. import bpy class TEST_OT_poll(): @classmethod def poll(cls, context): if context.space_data.type == 'NODE_EDITOR' and context.space_data.tree_type == 'ShaderNodeTree': return True else: return False class TEST_OT_make_group(bpy.types.Operator, TEST_OT_poll): bl_idname = "node.test_make_group" bl_label = "Make Group" bl_description = "" bl_options = {'REGISTER', 'UNDO'} def execute(self, context): bpy.ops.node.group_make() bpy.ops.node.group_edit(exit=True) return {'FINISHED'} class TEST_PT_panel(bpy.types.Panel): bl_idname = "TEST_PT_panel" bl_label = "Make group" bl_space_type = 'NODE_EDITOR' bl_region_type = "UI" bl_category = "Tool" @classmethod def poll(cls, context): if context.space_data.tree_type == 'ShaderNodeTree': return True else: return False def draw(self, context): layout = self.layout column = layout.column() column.operator("node.test_make_group", text = "Make Group") classes = ( TEST_PT_panel, TEST_OT_make_group, ) def register(): for c in classes: bpy.utils.register_class(c) def unregister(): for c in classes: bpy.utils.unregister_class(c) if __name__ == "__main__": register() [1]: https://docs.blender.org/api/current/bpy.ops.html#overriding-context [2]: https://i.sstatic.net/xJJFH.gif