diff --git a/docs/content/getting-started/faq.md b/docs/content/getting-started/faq.md
index 0875044525ba74d1a779abba202e6e435a080dd8..01b33f6398ac242516b976d07edee89b4cac5260 100644
--- a/docs/content/getting-started/faq.md
+++ b/docs/content/getting-started/faq.md
@@ -157,3 +157,27 @@ By default, the following headers are automatically added when proxying requests
 
 For more details,
 please check out the [forwarded header](../routing/entrypoints.md#forwarded-headers) documentation.
+
+## What does the "field not found" error mean?
+
+```shell
+error: field not found, node: -badField-
+```
+
+The "field not found" error occurs, when an unknown property is encountered in the dynamic or static configuration.
+
+One easy way to check whether a configuration file is well-formed, is to validate it with:
+
+- [JSON Schema of the static configuration](https://json.schemastore.org/traefik-v2.json)
+- [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json)
+
+## Why are some resources (routers, middlewares, services...) not created/applied?
+
+As a common tip, if a resource is dropped/not created by Traefik after the dynamic configuration was evaluated,
+one should look for an error in the logs.
+
+If found, the error obviously confirms that something went wrong while creating the resource,
+and the message should help in figuring out the mistake(s) in the configuration, and how to fix it.
+
+When using the file provider,
+one easy way to check if the dynamic configuration is well-formed is to validate it with the [JSON Schema of the dynamic configuration](https://json.schemastore.org/traefik-v2-file-provider.json).
diff --git a/docs/content/routing/routers/index.md b/docs/content/routing/routers/index.md
index d5ef084a6dde54b3c501e6affbda12c5e211c1e1..3a5045a27edb2aeb2995d662410994ba1cce7e8d 100644
--- a/docs/content/routing/routers/index.md
+++ b/docs/content/routing/routers/index.md
@@ -233,18 +233,18 @@ If the rule is verified, the router becomes active, calls middlewares, and then
 
 The table below lists all the available matchers:
 
-| Rule                                                                   | Description                                                                                                    |
-|------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
-| ```Headers(`key`, `value`)```                                          | Check if there is a key `key`defined in the headers, with the value `value`                                    |
-| ```HeadersRegexp(`key`, `regexp`)```                                   | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
-| ```Host(`example.com`, ...)```                                         | Check if the request domain (host header value) targets one of the given `domains`.                            |
-| ```HostHeader(`example.com`, ...)```                                   | Same as `Host`, only exists for historical reasons.                                                            |
-| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)``` | Match the request domain. See "Regexp Syntax" below.                                                           |
-| ```Method(`GET`, ...)```                                               | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`)    |
-| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)```         | Match exact request path. See "Regexp Syntax" below.                                                           |
-| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)```   | Match request prefix path. See "Regexp Syntax" below.                                                          |
-| ```Query(`foo=bar`, `bar=baz`)```                                      | Match Query String parameters. It accepts a sequence of key=value pairs.                                       |
-| ```ClientIP(`10.0.0.0/16`, `::1`)```                                   | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats.            |
+| Rule                                                                                       | Description                                                                                                    |
+|--------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------|
+| ```Headers(`key`, `value`)```                                                              | Check if there is a key `key`defined in the headers, with the value `value`                                    |
+| ```HeadersRegexp(`key`, `regexp`)```                                                       | Check if there is a key `key`defined in the headers, with a value that matches the regular expression `regexp` |
+| ```Host(`example.com`, ...)```                                                             | Check if the request domain (host header value) targets one of the given `domains`.                            |
+| ```HostHeader(`example.com`, ...)```                                                       | Same as `Host`, only exists for historical reasons.                                                            |
+| ```HostRegexp(`example.com`, `{subdomain:[a-z]+}.example.com`, ...)```                     | Match the request domain. See "Regexp Syntax" below.                                                           |
+| ```Method(`GET`, ...)```                                                                   | Check if the request method is one of the given `methods` (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`)    |
+| ```Path(`/path`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`, ...)```                             | Match exact request path. See "Regexp Syntax" below.                                                           |
+| ```PathPrefix(`/products/`, `/articles/{cat:[a-z]+}/{id:[0-9]+}`)```                       | Match request prefix path. See "Regexp Syntax" below.                                                          |
+| ```Query(`foo=bar`, `bar=baz`)```                                                          | Match Query String parameters. It accepts a sequence of key=value pairs.                                       |
+| ```ClientIP(`10.0.0.0/16`, `::1`)```                                                       | Match if the request client IP is one of the given IP/CIDR. It accepts IPv4, IPv6 and CIDR formats.            |
 
 !!! important "Non-ASCII Domain Names"
 
@@ -259,6 +259,7 @@ The table below lists all the available matchers:
     The regexp name (`name` in the above example) is an arbitrary value, that exists only for historical reasons.
 
     Any `regexp` supported by [Go's regexp package](https://golang.org/pkg/regexp/) may be used.
+    For example, here is a case insensitive path matcher syntax: ```Path(`/{path:(?i:Products)}`)```.
 
 !!! info "Combining Matchers Using Operators and Parenthesis"
 
diff --git a/pkg/plugins/middlewares.go b/pkg/plugins/middlewares.go
index 09edbc9543b029e49ca73f60591309a3bc94d4f3..e46dbae3441e0d110762e3bae9047e9fca6dedd0 100644
--- a/pkg/plugins/middlewares.go
+++ b/pkg/plugins/middlewares.go
@@ -84,6 +84,9 @@ func (p middlewareBuilder) createConfig(config map[string]interface{}) (reflect.
 	}
 
 	vConfig := results[0]
+	if len(config) == 0 {
+		return vConfig, nil
+	}
 
 	cfg := &mapstructure.DecoderConfig{
 		DecodeHook:       mapstructure.StringToSliceHookFunc(","),
diff --git a/pkg/server/middleware/plugins.go b/pkg/server/middleware/plugins.go
index a401791514f9ca7141660ca13e001ead1c7757c9..3a092f140884191aa4bca81f14bed5110cd7d27a 100644
--- a/pkg/server/middleware/plugins.go
+++ b/pkg/server/middleware/plugins.go
@@ -2,7 +2,6 @@ package middleware
 
 import (
 	"errors"
-	"fmt"
 
 	"github.com/traefik/traefik/v2/pkg/config/dynamic"
 	"github.com/traefik/traefik/v2/pkg/plugins"
@@ -30,9 +29,5 @@ func findPluginConfig(rawConfig map[string]dynamic.PluginConf) (string, map[stri
 		return "", nil, errors.New("missing plugin type")
 	}
 
-	if len(rawPluginConfig) == 0 {
-		return "", nil, fmt.Errorf("missing plugin configuration: %s", pluginType)
-	}
-
 	return pluginType, rawPluginConfig, nil
 }