Creating a npm package: Meteor code must always run within a Fiber

Hey guys,
I had to create a private npm package for our internal model which we want to reuse in multiple apps. When I import the model like this:

import {createModel} from "model";

and calling the save function of a new document, I get the following error message:

 Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.

When I now copy the content of our createModel function into a seperate file and import it like this:

    import {createModel} from "/imports/others/model.js";

everything is working fine. Does anybody have an idea how I can fix this issue? Wrapping it with Meteor.bindEnvironment didn’t help.

I’d console.log for createModel and see what it is…
I don’t know if you use and .npmrc and what configurations you have in it but the easiest way to go forward would be to locally install your npm package.

Say in your root directory create a localNPM folder. Add your package folder there and install it with
npm i "file:localNPM/packagename." You can name it something like ‘@xta/model’ to recognize it beside the official NPMs from the public repos or @xta-local.

If all ok you can publish it somewhere as a private package.

Everything is okay there, I get the structure for the model when I do a console.log. The only issue is the save function which also triggers an event for redis-oplog:

W20230717-17:12:15.693(2)? (STDERR) (node:2271) UnhandledPromiseRejectionWarning: Error: Meteor code must always run within a Fiber. Try wrapping callbacks that you pass to non-Meteor libraries with Meteor.bindEnvironment.
W20230717-17:12:15.693(2)? (STDERR)     at Object.Meteor._nodeCodeMustBeInFiber (packages/meteor.js:1320:11)
W20230717-17:12:15.693(2)? (STDERR)     at Meteor.EnvironmentVariable.EVp.get (packages/meteor.js:1345:10)
W20230717-17:12:15.694(2)? (STDERR)     at packages/cultofcoders:redis-oplog/lib/mongo/lib/getMutationConfig.js:17:39
W20230717-17:12:15.694(2)? (STDERR)     at hook.insert (packages/cultofcoders:redis-oplog/lib/mongo/Mutator.js:53:24)
W20230717-17:12:15.694(2)? (STDERR)     at hook.insert (packages/cultofcoders:redis-oplog/lib/mongo/extendMongoCollection.js:29:35)
W20230717-17:12:15.694(2)? (STDERR)     at hook.Mongo.Collection.<computed> [as insertAsync] (packages/mongo/collection.js:1003:46)

What I don’t understand is why it works if I copy the createModel function into a project file and fails if I import it via a npm package? Does Meteor thread such imports differently?

Ok, an opinion but I am not 100% on it. Ok … maybe 20% max :)))

"/imports/others/model.js" is both client and server because is not in a “server” folder.
If you call createModel inside a Method which you call from the client, it may run with the stub.
When you install an NPM and you import from NPM you import server side only and you run everything on the server, thus the need for binding to the environment.
I don’t know your code structure but perhaps try to run everything async or bind to the environment.

const bound = Meteor.bindEnvironment(callback => callback())
 bound(() => { /* put all your relevant code here.  */ })

1 Like

Yees, it is the right direction. I’ve checked the this context within the createModel function. If I import it via my project files, the function is bound to the Meteor environment. If I import it via npm, the this context is undefined.

This fixed the issue, but I have to check if I can do the bindEnvironment within the npm package so it gets binded automatically:

import {createModel} from 'model';
const createModelBinded = createModel.bind(this);

Worth it to condition it on the existing of Fibers to have it working with Meteor 3 too. Not sure if there will be any bounding in the future.

I already called only the async functions to avoid fibers, but it seems that redis-oplog still depends on it, so I hope they will fix it soon after Meteor 3 has been released.

Mhh seems that this wasn’t the solution. I really don’t understand why it works if I add the content straight within a project file or within an internal meteor package, but fails if I import the code via npm. It seems that there is something different with the bindings, but I wasn’t able to bind it corretly with .bind or Meteor.bindEnvironment.

The function looks like this:

function createModel({name, collection, schema, events, helpers, relations}) {
   function Model(params) {
       [...]

      this.save = async function() {
           [...]
           await Model.collection.insertAsync(cleanedValues); // Native async insert function of Meteor
       }
   }

  return Model;
}

export {createModal};
1 Like

ok … try:

const bound = Meteor.bindEnvironment(callback => callback())

function createModel({name, collection, schema, events, helpers, relations}) {
   function Model(params) {
       [...]

      this.save = async function() {
           [...]
           await Model.collection.insertAsync(cleanedValues); // Native async insert function of Meteor
       }
   }

  return bound(() => Model);
}

This also gives me the error, that I need to run the code within a Fiber.

Any progress on this issue?

Will this become a no issue for Meteor 3?

Yes :slight_smile:

This is one of the benefits of removing Fibers: alignment with the Node.js ecosystem.