handlebars.js: Handlebars: Access has been denied to resolve the property "..." because it is not an "own property" of its parent.

Since Handlebars 4.6.0, templates cannot access prototype properties and methods anymore (by default). See #1633 for discussios, reasons and justifications.

There are runtime options to restore and control the old behavior (see https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access), but if you are using a framework instead of Handlebars core, it might not be clear how to set them.

If you get this error message and please add a comment with the following information

  • Which framework (i.e express-hbs, express-handlebars) is calling Handlebars when the error is logged? (Paste the output of npm ls handlebars or yarn why handlebars, if unsure).
  • If you use Handlebars.compile and the resulting template-function directly, you answer should be here https://handlebarsjs.com/api-reference/runtime-options.html#options-to-control-prototype-access. If the documentation doesn’t answer your question or you don’t understand it, please ask (here) so that the documentation can be improved.

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 5
  • Comments: 15

Most upvoted comments

Frameworks: express-handlebars in conjunction with mongoose

The models of Mongoose are classes and the properties are not “own properties” of the parent object.

The cleanest method is to make sure the the handlebars-input is a proper plain javascript object. This can be done in Mongoose, by calling toJSON() or toObject

app.get('/test', function (_req, res) {
    Kitten.find({}).then(kittens => {
        res.render('test.hbs', {
            kittens: kittens.map(kitten => kitten.toJSON())
        })
    })
});

The runtimeOptions (or templateOptions) mentioned in the documenation cannot be used here, because express-handlebars does not support setting them.

The quick-and-dirty hack (which is really hacky and I don’t propose is), is to use

var handlebarsInstance = Handlebars.create();

handlebarsInstance.compile = function (templateStr, compileOptions) {
   // compile template
   // return a function that calls the compiled template with  `allowProtoPropertiesByDefault` and `allowProtoMethodsByDefault` as runtime-options
  // WARNING: People can crash your system by frabricating special templates. Don't use
  // this if your users can create templates. 
}
app.engine('hbs', expressHandlebars({
    handlebars: handlebarsInstance
}));

Please add a Rocket-emoji to this comment if you would like to have a Handlebars.createWithAllowedProtoAccess or something like that that does the middle part for you.

@Invogue01 You should be able to use the runtimeOptions parameter in express-handlebars

const hbs = exphbs.create({
  defaultLayout: 'main', 
  extname: 'hbs',
  runtimeOptions: {
    allowProtoPropertiesByDefault: true,
    allowProtoMethodsByDefault: true
  }
});

Frameworks: express-handlebars in conjunction with mongoose

The models of Mongoose are classes and the properties are not “own properties” of the parent object.

The cleanest method is to make sure the the handlebars-input is a proper plain javascript object. This can be done in Mongoose, by calling toJSON() or toObject

app.get('/test', function (_req, res) {
    Kitten.find({}).then(kittens => {
        res.render('test.hbs', {
            kittens: kittens.map(kitten => kitten.toJSON())
        })
    })
});

The runtimeOptions (or templateOptions) mentioned in the documenation cannot be used here, because express-handlebars does not support setting them.

The quick-and-dirty hack (which is really hacky and I don’t propose is), is to use

var handlebarsInstance = Handlebars.create();

handlebarsInstance.compile = function (templateStr, compileOptions) {
   // compile template
   // return a function that calls the compiled template with  `allowProtoPropertiesByDefault` and `allowProtoMethodsByDefault` as runtime-options
  // WARNING: People can crash your system by frabricating special templates. Don't use
  // this if your users can create templates. 
}
app.engine('hbs', expressHandlebars({
    handlebars: handlebarsInstance
}));

Please add a Rocket-emoji to this comment if you would like to have a Handlebars.createWithAllowedProtoAccess or something like that that does the middle part for you.

We can alose use lean() method as shown below

 app.get('/test', function (_req, res) {
    Kitten.find().lean().then(kittens => res.render('test.hbs', { kittens: kittens}));
});