diff --git a/src/blocks/scratch3_procedures.js b/src/blocks/scratch3_procedures.js
index c648d9603..b91630f12 100644
--- a/src/blocks/scratch3_procedures.js
+++ b/src/blocks/scratch3_procedures.js
@@ -27,11 +27,20 @@ class Scratch3ProcedureBlocks {
         if (!util.stackFrame.executed) {
             const procedureCode = args.mutation.proccode;
             const paramNames = util.getProcedureParamNames(procedureCode);
+
+            // If null, procedure could not be found, which can happen if custom
+            // block is dragged between sprites without the definition.
+            // Match Scratch 2.0 behavior and noop.
+            if (paramNames === null) {
+                return;
+            }
+
             for (let i = 0; i < paramNames.length; i++) {
                 if (args.hasOwnProperty(`input${i}`)) {
                     util.pushParam(paramNames[i], args[`input${i}`]);
                 }
             }
+
             util.stackFrame.executed = true;
             util.startProcedure(procedureCode);
         }
diff --git a/test/unit/blocks_procedures.js b/test/unit/blocks_procedures.js
new file mode 100644
index 000000000..4ecdb41d8
--- /dev/null
+++ b/test/unit/blocks_procedures.js
@@ -0,0 +1,28 @@
+const test = require('tap').test;
+const Procedures = require('../../src/blocks/scratch3_procedures');
+
+const blocks = new Procedures(null);
+
+test('getPrimitives', t => {
+    t.type(blocks.getPrimitives(), 'object');
+    t.end();
+});
+
+// Originally inspired by https://github.com/LLK/scratch-gui/issues/809
+test('calling a custom block with no definition does not throw', t => {
+    const args = {
+        mutation: {
+            proccode: 'undefined proc'
+        }
+    };
+    const util = {
+        getProcedureParamNames: () => null,
+        stackFrame: {
+            executed: false
+        }
+    };
+    t.doesNotThrow(() => {
+        blocks.callNoReturn(args, util);
+    });
+    t.end();
+});