Skip to content

unknown(false) is not work when configuration "allowUnknown" is true #2824

@LuEason

Description

@LuEason

Support plan

  • is this issue currently blocking your project? (yes/no): yes
  • is this issue affecting a production system? (yes/no): yes

Context

  • node version: 14.20.0
  • module version: 17.6.0
  • environment (e.g. node, browser, native): node
  • used with (e.g. hapi application, another framework, standalone, ...): node
  • any other relevant information:

How can we help?

Our project use version 14 before, we want to allow all fields of all object except for some fields we don't expect
For example, we want to allow field "e" of data.d only, and allow other unknown fields for data.b and even data, we use below code:

const joi = require('joi');

const schema = joi.object().keys({
  a: joi.string(),
  b: joi.object().keys({
    c: joi.string()
  }),
  d: joi.object().keys({
    e: joi.string()
  }).unknown(false)
});

const value = {
  a: '123',
  b: {
    c: '123',
    f: 123
  },
  d: {
    e: '12',
    g: 123
  },
  h: 123
};

const result = schema.validate(value, {
  abortEarly: false,
  allowUnknown: true
});

console.log(result?.error?.message);
// child "d" fails because ["g" is not allowed]

After we use version 17, the data pass the validation, which we do not expect.

Do you have any suggestions?

Activity

added
supportQuestions, discussions, and general support
on Aug 23, 2022
Marsup

Marsup commented on Aug 23, 2022

@Marsup
Collaborator

It looks like a bug. In the meantime, you can replace .unknown(false) by .options({ allowUnknown: false }), just beware that it's inherited by children schemas.

LuEason

LuEason commented on Aug 24, 2022

@LuEason
Author

Thanks Marsup.
By the way, I look up the source code and found where is this error caused. It is in /lib/base.js.

$_setFlag(name, value, options = {}) {

        Assert(name[0] === '_' || !this._inRuleset(), 'Cannot set flag inside a ruleset');

        const flag = this._definition.flags[name] || {};
        if (DeepEqual(value, flag.default)) {
            value = undefined;
        }

        if (DeepEqual(value, this._flags[name])) {
            return this;
        }
}

It is so weird to set the value to undefined when value same as the default value of flag. But once I delete this if statement, many tests failed. Please help have a check.

geeksilva97

geeksilva97 commented on Sep 30, 2022

@geeksilva97

Hi folks. Could I work on that issue?

Marsup

Marsup commented on Sep 30, 2022

@Marsup
Collaborator

It's not the easiest one but sure.

geeksilva97

geeksilva97 commented on Oct 5, 2022

@geeksilva97

Thanks @Marsup .

geeksilva97

geeksilva97 commented on Oct 5, 2022

@geeksilva97

Hi, @LuEason I tested this code you sent using Joi 17.6.1 and it looks like it works as you expect.

It doesn't have any errors. When I print the result I get the following:

{
  value: { a: '123', b: { c: '123', f: 123 }, d: { e: '12', g: 123 }, h: 123 }
}

Maybe it was already fixed @Marsup .

Marsup

Marsup commented on Oct 11, 2022

@Marsup
Collaborator

@geeksilva97 that's precisely the problem, it should fail on object d because g is not allowed.

kamweti

kamweti commented on Nov 15, 2022

@kamweti

@Marsup

It looks like a bug

This is expected:

from the docs

allowUnknown - when true, allows object to contain unknown keys which are ignored. Defaults to false.

allowUknown will override any .unknown(false) settings you have

const schema = joi.object().keys({
    foo: joi.object().keys({
        bar: joi.string()
    }).unknown(false)
})

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    })
) // "foo.baaz" is not allowed

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    }, {allowUnknown: true})
) // valid

@LuEason

you can turn on this feature by not passing allowUnknown: true and instead add granular uknown(false) entries to the your desired keys

Marsup

Marsup commented on Nov 15, 2022

@Marsup
Collaborator

Local should always override global, it is imo a bug.

kamweti

kamweti commented on Nov 15, 2022

@kamweti

fair enough, i now see this is what happens in the yup lib as well

const schema = yup.object().shape({
    foo: yup.object({
        bar: yup.string()
    }).noUnknown(true)
})

console.log(
    schema.validate({
        foo: {
            bar: "bar",
            baaz: "baaz"
        }
    }, {stripUnknown: false})
) // foo field has unspecified keys: baaz
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug or defectsupportQuestions, discussions, and general support

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @kamweti@Marsup@geeksilva97@LuEason

      Issue actions

        unknown(false) is not work when configuration "allowUnknown" is true · Issue #2824 · hapijs/joi