function checkValueAgainstSchema (context, property, jsonPathPrefix, txnParamName, value, schemaPathPrefix,
  openApiSchemaObj, parameterSourceOption, components, options, schemaCache, jsonSchemaDialect, callback) {

  let mismatches = [],
    jsonValue,
    humanPropName = propNames[property],
    needJsonMatching = (property === 'BODY' || property === 'RESPONSE_BODY'),
    invalidJson = false,
    valueToUse = value,

    schema = resolveSchema(context, openApiSchemaObj, {
      resolveFor: PROCESSING_TYPE.VALIDATION,
      isResponseSchema: parameterSourceOption === PARAMETER_SOURCE.RESPONSE
    }),
    compositeSchema = schema.oneOf || schema.anyOf,
    compareTypes = _.get(context, 'concreteUtils.compareTypes') || concreteUtils.compareTypes;

  if (needJsonMatching) {
    try {
      jsonValue = JSON.parse(value);
      // If valid JSON is detected, the parsed value should be used
      // to determine mismatches
      valueToUse = jsonValue;
    }
    catch (e) {
      jsonValue = '';
      invalidJson = true;
    }
  }

  // For anyOf and oneOf schemas, validate value against each schema and report result with least mismatches
  if (compositeSchema) {
    // get mismatches of value against each schema
    async.map(compositeSchema, (elementSchema, cb) => {
      setTimeout(() => {
        checkValueAgainstSchema(context, property, jsonPathPrefix, txnParamName, value,
          `${schemaPathPrefix}.${schema.oneOf ? 'oneOf' : 'anyOf'}[${_.findIndex(compositeSchema, elementSchema)}]`,
          elementSchema, parameterSourceOption, components, options, schemaCache, jsonSchemaDialect, cb);
      }, 0);
    }, (err, results) => {
      let sortedResults;

      if (err) {
        return callback(err, []);
      }

      // return mismatches of schema against which least validation mismatches were found
      sortedResults = _.sortBy(results, (res) => { return res.length; });
      return callback(null, sortedResults[0]);
    });
  }
  // When processing a reference, schema.type could also be undefined
  else if (schema && schema.type) {
    if (isKnownType(schema)) {
      let isCorrectType;

      // Treat unresolved postman collection/environment variable as correct type
      if (options.ignoreUnresolvedVariables && isPmVariable(valueToUse)) {
        isCorrectType = true;
      }
      else {
        isCorrectType = checkIsCorrectType(valueToUse, schema);
      }

      if (!isCorrectType) {
        // if type didn't match, no point checking for AJV
        let reason = '',
          mismatchObj;

        // exclude mismatch errors for nested objects in parameters (at this point simple objects and array should
        // be already converted to primitive schema and only nested objects remains as type object/array)
        if (_.includes(['QUERYPARAM', 'PATHVARIABLE', 'HEADER'], property) &&
          (compareTypes(schema.type, 'object') || compareTypes(schema.type, 'array'))) {
          return callback(null, []);
        }

        if (property === 'RESPONSE_BODY' || property === 'BODY') {
          // we don't have names for the body, but there's only one
          reason = 'The ' + humanPropName;
        }
        else if (txnParamName) {
          // for query params, req/res headers, path vars, we have a name. Praise the lord.
          reason = `The ${humanPropName} "${txnParamName}"`;
        }
        else {
          // for query params, req/res headers, path vars, we might not ALWAYS have a name.
          reason = `A ${humanPropName}`;
        }
        reason += ` needs to be of type ${schema.type}, but we found `;
        if (!options.shortValidationErrors) {
          reason += `"${valueToUse}"`;
        }
        else if (invalidJson) {
          reason += 'invalid JSON';
        }
        else if (Array.isArray(valueToUse)) {
          reason += 'an array instead';
        }
        else if (typeof valueToUse === 'object') {
          reason += 'an object instead';
        }
        else {
          reason += `a ${typeof valueToUse} instead`;
        }

        mismatchObj = {
          property,
          transactionJsonPath: jsonPathPrefix,
          schemaJsonPath: schemaPathPrefix,
          reasonCode: 'INVALID_TYPE',
          reason
        };

        if (options.suggestAvailableFixes) {
          mismatchObj.suggestedFix = {
            key: txnParamName,
            actualValue: valueToUse,
            suggestedValue: safeSchemaFaker(context, schema || {}, PROCESSING_TYPE.VALIDATION,
              parameterSourceOption, components, SCHEMA_FORMATS.DEFAULT, schemaCache)
          };
        }

        return callback(null, [mismatchObj]);
      }

      // only do AJV if type is array or object
      // simpler cases are handled by a type check
      if (isCorrectType && needJsonMatching) {
        let filteredValidationError = validateSchema(schema, valueToUse, options, jsonSchemaDialect);

        if (!_.isEmpty(filteredValidationError)) {
          let mismatchObj,
            suggestedValue,
            fakedValue = safeSchemaFaker(context, schema || {}, PROCESSING_TYPE.VALIDATION,
              parameterSourceOption, components, SCHEMA_FORMATS.DEFAULT, schemaCache);

          // Show detailed validation mismatches for only request/response body
          if (options.detailedBlobValidation && needJsonMatching) {
            _.forEach(filteredValidationError, (ajvError) => {
              let localSchemaPath = ajvError.schemaPath.replace(/\//g, '.').slice(2),
                dataPath = formatDataPath(ajvError.instancePath || '');

              // discard the leading '.' if it exists
              if (dataPath[0] === '.') {
                dataPath = dataPath.slice(1);
              }

              mismatchObj = _.assign({
                property: property,
                transactionJsonPath: jsonPathPrefix + formatDataPath(ajvError.instancePath),
                schemaJsonPath: schemaPathPrefix + '.' + localSchemaPath
              }, ajvValidationError(ajvError, { property, humanPropName }));

              if (options.suggestAvailableFixes) {
                mismatchObj.suggestedFix = {
                  key: _.split(dataPath, '.').pop(),
                  actualValue: getPathValue(valueToUse, dataPath, null),
                  suggestedValue: getSuggestedValue(fakedValue, valueToUse, ajvError)
                };
              }
              mismatches.push(mismatchObj);
            });
          }
          else {
            mismatchObj = {
              reason: `The ${humanPropName} didn\'t match the specified schema`,
              reasonCode: 'INVALID_TYPE'
            };

            // assign proper reason codes for invalid body
            if (property === 'BODY') {
              mismatchObj.reasonCode = 'INVALID_BODY';
            }
            else if (property === 'RESPONSE_BODY') {
              mismatchObj.reasonCode = 'INVALID_RESPONSE_BODY';
            }

            if (options.suggestAvailableFixes) {
              suggestedValue = _.cloneDeep(valueToUse);

              // Apply each fix individually to respect existing values in request
              _.forEach(filteredValidationError, (ajvError) => {
                let dataPath = formatDataPath(ajvError.instancePath || '');

                // discard the leading '.' if it exists
                if (dataPath[0] === '.') {
                  dataPath = dataPath.slice(1);
                }

                // for empty string _.set creates new key with empty string '', so separate handling
                if (dataPath === '') {
                  suggestedValue = getSuggestedValue(fakedValue, suggestedValue, ajvError);
                }
                else {
                  _.set(suggestedValue, dataPath, getSuggestedValue(fakedValue, suggestedValue, ajvError));
                }
              });

              mismatchObj.suggestedFix = {
                key: property.toLowerCase(),
                actualValue: valueToUse,
                suggestedValue
              };
            }

            mismatches.push(_.assign({
              property: property,
              transactionJsonPath: jsonPathPrefix,
              schemaJsonPath: schemaPathPrefix
            }, mismatchObj));
          }

          // only return AJV mismatches
          return callback(null, mismatches);
        }
        // result passed. No AJV mismatch
        return callback(null, []);
      }

      // Schema was not AJV or object
      // Req/Res Body was non-object but content type is application/json
      else if (needJsonMatching) {
        return callback(null, [{
          property,
          transactionJsonPath: jsonPathPrefix,
          schemaJsonPath: schemaPathPrefix,
          reasonCode: 'INVALID_TYPE',
          reason: `The ${humanPropName} needs to be of type object/array, but we found "${valueToUse}"`,
          suggestedFix: {
            key: null,
            actualValue: valueToUse,
            suggestedValue: {} // suggest value to be object
          }
        }]);
      }
      else {
        return callback(null, []);
      }
    }
    else {
      // unknown schema.type found
      // TODO: Decide how to handle. Log?
      return callback(null, []);
    }
  }
  // Schema not defined
  else {
    return callback(null, []);
  }
}
@param {Object} context - Required context from related SchemaPack function
@param {String} property - one of QUERYPARAM, PATHVARIABLE, HEADER, BODY, RESPONSE_HEADER, RESPONSE_BODY
@param {String} jsonPathPrefix - this will be prepended to all JSON schema paths on the request
@param {String} txnParamName - Optional - The name of the param being validated (useful for query params,
 req headers, res headers)
@param {*} value - the value of the property in the request
@param {String} schemaPathPrefix - this will be prepended to all JSON schema paths on the schema
@param {Object} openApiSchemaObj - The OpenAPI schema object against which to validate
@param {String} parameterSourceOption tells that the schema object is of request or response
@param {Object} components - Components in the spec that the schema might refer to
@param {Object} options - Global options
@param {Object} schemaCache object storing schemaFaker and schemaResolution caches
@param {string} jsonSchemaDialect The schema dialect defined in the OAS object
@param {Function} callback - For return
@returns {Array} array of mismatches