Skip to main content

Troubleshoot

This page describes common issues you may encounter when developing a snap, and how to resolve them.

If you encounter any issues that you can't solve on your own, please open a GitHub issue.

Fix build and evaluation issues

Because Secure EcmaScript (SES) adds additional restrictions on the JavaScript runtime on top of strict mode, code that executes normally under strict mode might not under SES. mm-snap build by default attempts to execute a snap in a stubbed SES environment. You can also disable this behavior and run the evaluation step separately using mm-snap eval. If an error is thrown during this step, it's likely due to a SES incompatibility, and you must fix the issues manually. These incompatibilities tend to occur in dependencies.

While the errors you get from SES may seem scary, they're usually not that hard to fix. The actual file, function, and variable names in the mm-snap eval error stack trace might not make a lot of sense to you, but the line numbers should correspond to your snap bundle file. Thus, you can identify if the error is due to your code or one of your dependencies. If the problem is in a dependency, you can try a different version or to fix the issue locally by using tools such as patch-package (see how to patch dependencies) or by modifying the bundle file directly.

To give you an idea of a common error and how to fix it, "sloppily" declared variables (i.e. assigning to a new variable without an explicit variable declaration) are forbidden in strict mode, and therefore in SES as well. If you get an error during the eval step that says something like variableName is not defined, simply prepending var variableName; to your snap bundle may solve the problem. (This actually happened so frequently with Babel's regeneratorRuntime that mm-snap build automatically handles that one.)

caution

Run mm-snap manifest --fix if you modified your snap bundle after building. Otherwise your manifest shasum value won't be correct, and attempting to install your snap fails.

Use other build tools

If you prefer building your snap with a build system you're more comfortable with, Snaps implements plugins for several other build systems:

For examples on how to set up these build systems yourself, please see the examples.

We still recommend using the Snaps CLI to make sure your manifest shasum value is correct, by running mm-snap manifest --fix after creating your bundle. You may also benefit from running mm-snap eval to detect any SES issues up front.

Patch dependencies

Some dependencies might make use of APIs that aren't available in the Snaps execution environment. To work around this, we recommend checking if another library is available that makes use of those APIs.

If you can't find another library (or version) that works with the Snaps execution environment, you can patch the dependency yourself using patch-package.

patch-package allows you to make changes to your dependencies, saving the changes as a patch and replaying it when installing dependencies.

Install patch-package using Yarn:

yarn add -D patch-package postinstall-postinstall

Then add a postinstall script to your package.json:

 "scripts": {
+ "postinstall": "patch-package"
}

Now you can make changes to your dependencies inside node_modules and run yarn patch-package package-name to save the changes as a patch. This creates a .patch file containing your dependency patch. These patches can be committed to your Git repository and are replayed when you re-install your dependencies.

Patch the use of XMLHttpRequest

The XMLHttpRequest API is not exposed in the Snaps execution environment and won't be in the future. Because of this, you may run into issues with dependencies in your dependency tree attempting to use this API for their network requests.

The following are examples of popular libraries that use XMLHttpRequest and are thus not compatible with the Snaps execution environment. This section also describes patching strategies for fixing dependencies that try to use these libraries.

cross-fetch

cross-fetch is a popular library used for cross-platform access to the fetch API across multiple environments. Under the hood, however, the library uses XMLHttpRequest and thus causes issues when used in a snap.

You can easily patch this issue using patch-package. Open node_modules/cross-fetch/browser-ponyfill.js and find the following lines near the bottom of the file:

// Choose between native implementation (global) or custom implementation (__self__)
// var ctx = global.fetch ? global : __self__;
var ctx = __self__; // this line disable service worker support temporarily

You can replace that with the following snippet:

// Choose between native implementation (global) or custom implementation (__self__)
var ctx = global.fetch
? { ...global, fetch: global.fetch.bind(global) }
: __self__;
// var ctx = __self__; // this line disable service worker support temporarily

After replacing it, run yarn patch-package cross-fetch, which saves the patch for future use.

Alternatively, you can use the following patch, copy and paste it to patches/cross-fetch+3.1.5.patch, and re-install your dependencies:

diff --git a/node_modules/cross-fetch/dist/browser-ponyfill.js b/node_modules/cross-fetch/dist/browser-ponyfill.js
index f216aa3..6b3263b 100644
--- a/node_modules/cross-fetch/dist/browser-ponyfill.js
+++ b/node_modules/cross-fetch/dist/browser-ponyfill.js
@@ -543,8 +543,8 @@ __self__.fetch.ponyfill = true;
// Remove "polyfill" property added by whatwg-fetch
delete __self__.fetch.polyfill;
// Choose between native implementation (global) or custom implementation (__self__)
-// var ctx = global.fetch ? global : __self__;
-var ctx = __self__; // this line disable service worker support temporarily
+var ctx = global.fetch ? { ...global, fetch: global.fetch.bind(global) } : __self__;
+// var ctx = __self__; // this line disable service worker support temporarily
exports = ctx.fetch // To enable: import fetch from 'cross-fetch'
exports.default = ctx.fetch // For TypeScript consumers without esModuleInterop.
exports.fetch = ctx.fetch // To enable: import {fetch} from 'cross-fetch'

Using either of these methods allows your dependencies to access the fetch API correctly and cross-fetch compatible with the Snaps execution environment.

axios

axios is a popular networking library that uses XMLHttpRequest under the hood.

Currently, there's no known way of patching axios to work with the Snaps execution environment. Instead, you must replace axios with another library such as isomorphic-fetch or isomorphic-unfetch, or simply use the Snaps execution environment global fetch.

The following is an example of how you can rewrite your dependency to use fetch instead of axios.

note

In a production environment this may be a large task depending on the usage of axios.

axios

const instance = axios.create({
baseURL: 'https://api.github.com/',
});

instance
.get('users/MetaMask')
.then((res) => {
if (res.status >= 400) {
throw new Error('Bad response from server');
}
return res.data;
})
.then((user) => {
console.log(user);
})
.catch((err) => {
console.error(err);
});

fetch

fetch('https://api.github.com/users/MetaMask')
.then((res) => {
if (!res.ok) {
throw new Error('Bad response from server');
}
return res.json();
})
.then((json) => console.log(json))
.catch((err) => console.error(err));

More resources: