Click listener in browser action popup causing JS error

Firefox 57.0a1 (2017-08-10) (64-bit)

In my browser action popup, I dynamically build a set of buttons with a single click listener, and add them to the browser action popup DOM. But the click listener only works for the first click. Subsequent clicks while the popup is still visible result in a javascript error when calling console.log.

The listener is not defined inside a promise, and I’ve made sure it continues to exist and are defined. The behavior is very consistent.

HTML of browser_action default_popup:

<div id="container">
  <span id="btns"></span>
  <span id="btnTemplate" style="display: none">
    <input type="button" value="click me" data-foo="foo">
  </span>
</div>
...
<script src="scripts/jquery-2.2.4.js"></script>
<script src="scripts/popup.js"></script>

popup.js:

// Add 10 buttons
let btns = [];
for (let i=0; i<10; i++) {
  let template = $("#btnTemplate").html();
  btns.push(template);
}
$("#btns").html(''); // clear anything that's there
$("#btns").html(btns.join(''));
$('#container').on("click", "input[data-foo]", onClickButton);
$("#container").show();
...
function onClickButton(evt) {
  console.log('here'); // Javascript error on *THIS* line after first click
}
...

Clicking one of the buttons, I get ‘here’ displayed once in the console. Clicking any of the buttons again (even if it wasn’t clicked before–note they’re all sharing the same listener) yields this JS error:

Error: (the referenced line for the error in the console for the code console.log(‘here’);

error occurred while processing 'sources: TypeError: can't access dead object
Stack: createNonSourceMappedActor@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/utils/TabSources.js:299:1
createSourceActors/<@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/utils/TabSources.js:383:19
process@resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise-backend.js:922:23
walkerLoop@resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise-backend.js:806:7
Promise*scheduleWalkerLoop@resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise-backend.js:739:11
schedulePromise@resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise-backend.js:770:7
Promise.prototype.then@resource://gre/modules/Promise.jsm -> resource://gre/modules/Promise-backend.js:455:5
createSourceActors@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/utils/TabSources.js:382:12
_discoverSources/<@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/script.js:1338:14
_discoverSources@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/script.js:1337:16
onSources@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/actors/script.js:1343:12
onPacket@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/server/main.js:1797:15
receiveMessage@resource://gre/modules/commonjs/toolkit/loader.js -> resource://devtools/shared/transport/transport.js:761:7
Line: 299, column: 1  main.js:1660
	_unknownError resource://devtools/server/main.js:1660:5
	_queueResponse/responsePromise< resource://devtools/server/main.js:1678:25
	reject resource://devtools/shared/deprecated-sync-thenables.js:50:41
	then resource://devtools/shared/deprecated-sync-thenables.js:26:51
	resolve resource://devtools/shared/deprecated-sync-thenables.js:77:11
	reject resource://devtools/shared/deprecated-sync-thenables.js:51:16
	process resource://gre/modules/Promise-backend.js:925:21
	walkerLoop resource://gre/modules/Promise-backend.js:806:7
	bound walkerLoop self-hosted:945:17
	bound walkerLoop self-hosted:945:17

I have tried this without jquery and get the same results.

If the browser action popup is closed and re-opened, the above results are repeated.

Any ideas?

Thank you,
Eric