diff --git a/lib/types/keys.js b/lib/types/keys.js index a907c4d0..ce7d6895 100755 --- a/lib/types/keys.js +++ b/lib/types/keys.js @@ -990,7 +990,7 @@ internals.unknown = function (schema, value, unprocessed, errors, state, prefs) } } - const forbidUnknown = !Common.default(schema._flags.unknown, prefs.allowUnknown); + const forbidUnknown = !Common.default(schema._flags.unknown, (prefs.allowUnknown && !state.ancestors.length)); if (forbidUnknown) { for (const unprocessedKey of unprocessed) { const localState = state.localize([...state.path, unprocessedKey], []); diff --git a/test/index.js b/test/index.js index 2f4e46b4..8fb3e36d 100755 --- a/test/index.js +++ b/test/index.js @@ -397,6 +397,48 @@ describe('Joi', () => { Helper.validate(Joi.compile({ other: Joi.number() }), [[{ foo: 'bar' }, false, '"foo" is not allowed']]); }); + it('local unknown setting always overrides global allowUnknown setting', () => { + const input = { + a: { + b: "h", + c: "f" + }, + d: "h" + }; + + Helper.validate( + Joi.object({ + a: Joi.object().keys({ + b: Joi.string() + }).unknown(true) + }), + { allowUnknown: false }, + [[input, false, '"d" is not allowed']] + ); + + Helper.validate( + Joi.object({ + a: Joi.object().keys({ + b: Joi.string() + }).unknown(false) + }), + { allowUnknown: true }, + [[input, false, '"a.c" is not allowed']] + ); + + Helper.validate( + Joi.object({ + a: Joi.object().keys({ + b: Joi.string() + }) + }), + { allowUnknown: true }, + [[input, false, '"a.c" is not allowed']] + ); + + }); + + it('validates required key with multiple options', () => { const config = {