Skip to content

maxuru ~ % cat errors

Error string index

If a daemon printed something at you and you landed here, filter for it below. Each string is mapped to the one control page that fixes it.

Every entry names where it was read — a file in the daemon’s source, its own documentation, or its output. That is the same rule the CIS mappings follow: an invented error string costs exactly what a wrong benchmark id costs, so a string nobody has verified does not get an entry. Some pages therefore carry none, and that is a deliberate state rather than an oversight.

Two things worth knowing before you match on one:

Most of these are format strings, filled in at runtime. A path, a line number, a username or a port in an entry here is an illustration; yours will differ. Match on the fixed words around it.

Some are warnings, not failures. nginx logs [warn] for a user directive it is ignoring and starts anyway; RabbitMQ logs a resource alarm and keeps running while refusing publishes. A service that started is not evidence that its config was accepted in full.

74 strings from 40 pages across 8 services. Every one was read in the daemon's own source, its documentation, or its output.

Apache httpd20

AH00526: Syntax error on line 14 of /etc/apache2/apache2.conf: Argument for 'Require all' must be 'granted' or 'denied'
Require all takes exactly one of two words. Typos land here, and so does reaching for the 2.2 vocabulary — there is no `Require all deny`.Keep Require all denied on the root directoryapache/httpd modules/aaa/mod_authz_core.c
AH00526: Syntax error on line 14 of /etc/apache2/apache2.conf: Unknown Authz provider: valid-user
The word after Require is not a registered provider, which almost always means the module supplying it is not loaded. valid-user comes from mod_authz_user and ip comes from mod_authz_host; neither is implied by mod_authz_core.Keep Require all denied on the root directoryapache/httpd modules/aaa/mod_authz_core.c
AH01630: client denied by server configuration: /var/www/html/private
The runtime counterpart, logged each time a rule refuses a request. Seeing this is the control working — it is only a problem when the path surprises you, which is the usual sign that a broad Require all denied is shadowing a narrower grant.Keep Require all denied on the root directoryapache/httpd modules/aaa/mod_authz_core.c
AH02295: RewriteEngine in .htaccess forbidden by AllowOverride
The directive named at the front is the one being refused, and AllowOverride is why. This is what "my .htaccess is being ignored" actually looks like in the error log — the file is read, individual directives are just not permitted.Disable .htaccess with AllowOverride Noneapache/httpd server/config.c
AH00114: Useless use of AllowOverride in line 12 of /etc/apache2/apache2.conf
AllowOverride was written inside a <Location> or <Files> block, where it has no effect. It only applies in <Directory> blocks.Disable .htaccess with AllowOverride Noneapache/httpd server/core.c
AH00534: httpd: Configuration error: No MPM loaded.
The pruning went one module too far. An MPM is not optional and is not implied — exactly one of mpm_prefork, mpm_worker or mpm_event has to be loaded, and this is the only thing Apache says when none is.Disable unused Apache modulesapache/httpd server/mpm_common.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: Invalid command 'RewriteEngine', perhaps misspelled or defined by a module not included in the server configuration
The expected consequence of unloading a module, rather than a mistake in the line it points at — something in the config still depends on what was just removed. Search conf.d and the vhost files too, not only the main config, before concluding a module is unused.Disable unused Apache modulesapache/httpd server/config.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: Unknown Authz provider: ip
The Require line that was meant to lock /server-status down cannot be parsed, because ip is supplied by mod_authz_host and that module is not loaded. Apache refuses to start rather than serving the page unrestricted — but note the contrast with a Require line that is simply absent, which produces no error at all.Protect or disable Apache server-statusapache/httpd modules/aaa/mod_authz_core.c
AH01630: client denied by server configuration: /server-status
The restriction is working — this is logged every time an address outside the allow rule asks for the handler. Its absence in a log where you expected it is the finding, because it means the requests are being answered.Protect or disable Apache server-statusapache/httpd modules/aaa/mod_authz_core.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: Invalid command 'SSLProtocol', perhaps misspelled or defined by a module not included in the server configuration
mod_ssl is not loaded. Every SSL* directive vanishes with it, so a TLS block pasted into a server without mod_ssl fails on its first line rather than being quietly skipped.Configure Apache TLSapache/httpd server/config.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: SSLProtocol: Illegal protocol 'TLSv1.9'
The token is matched against a fixed list — TLSv1, TLSv1.1, TLSv1.2, TLSv1.3. A version that does not exist is rejected outright, which is worth contrasting with SSLCipherSuite — that one accepts an unrecognised cipher string at config-test time without complaint.Configure Apache TLSapache/httpd modules/ssl/ssl_engine_config.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: Invalid command 'Header', perhaps misspelled or defined by a module not included in the server configuration
mod_headers is not loaded. The directive is spelled correctly and the rest of the config is fine — Apache simply has no module claiming that name, so every header you meant to set is absent.Set Apache security headers correctlyapache/httpd server/config.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: first argument must be 'add', 'set', 'setifempty', 'append', 'merge', 'unset', 'echo', 'note', 'edit', or 'edit*'.
The action word is missing or misspelled. A condition keyword may come first — `Header always set X-Frame-Options DENY` is valid — but an action has to follow it, and naming the header straight after Header does not.Set Apache security headers correctlyapache/httpd modules/metadata/mod_headers.c
AH00526: Syntax error on line 12 of /etc/apache2/apache2.conf: ServerTokens takes 1 argument: 'Prod(uctOnly)', 'Major', 'Minor', 'Min(imal)', 'OS', or 'Full'
The value is not one of the six accepted words. Note what the list does not contain — there is no None and no Off, so this directive cannot remove the Server header, only shorten it.Turn off Apache directory listings and version bannersapache/httpd server/core.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: ServerSignature: use one of: off | on | email
ServerSignature is a separate control with its own vocabulary, and it governs the footer Apache appends to its own generated error pages — not the Server header. Setting one does nothing for the other.Turn off Apache directory listings and version bannersapache/httpd server/core.c
AH00526: Syntax error on line 14 of /etc/apache2/apache2.conf: ServerTokens not allowed in <Directory> context
ServerTokens is RSRC_CONF — server config and virtual hosts only. It cannot be scoped to a directory, a Files block or an .htaccess file, so there is no way to soften it for one path.Turn off Apache directory listings and version bannersapache/httpd server/config.c
AH00543: httpd: bad user name www-data
The User directive names an account that does not exist on this host — the usual cause is a config copied between distributions, which disagree on whether the account is www-data or apache. Apache exits rather than falling back, which is correct, because the fallback would be root.Run Apache workers as an unprivileged userapache/httpd server/mpm_common.c
AH00526: Syntax error on line 13 of /etc/apache2/apache2.conf: Invalid command 'User', perhaps misspelled or defined by a module not included in the server configuration
User and Group live in mod_unixd in 2.4, not in core. Without that module there is nothing to drop privileges with, so the daemon keeps whatever identity started it.Run Apache workers as an unprivileged userapache/httpd server/config.c
AH00037: Symbolic link not allowed or link target not accessible: /var/www/html/data
A symlink was walked and Options FollowSymLinks did not permit it. Useful as a signal rather than a fault — it names a path where the filesystem leaves the document root, which is the shape traversal attempts try to reach deliberately.The Apache path traversal (CVE-2021-41773)apache/httpd server/request.c
AH01630: client denied by server configuration: /etc/passwd
A traversal attempt that reached the filesystem and was stopped by an authorization rule. The path in the message is the resolved target, not the request URI — so a path outside the document root here means the escape worked and only the Require rule prevented the read.The Apache path traversal (CVE-2021-41773)apache/httpd modules/aaa/mod_authz_core.c

HAProxy2

[ALERT] parsing [/etc/haproxy/haproxy.cfg:42] : The 'reqirep' directive is not supported anymore since HAProxy 2.1. Use 'http-request replace-header' instead.
A fatal parse error, not a warning. The directive was removed, so the process refuses to start until the line is replaced or deleted.HAProxy reqadd, rspadd and reqirep were removedhaproxy/src/cfgparse-listen.c
[ALERT] parsing [/etc/haproxy/haproxy.cfg:42] : The 'rspadd' directive is not supported anymore since HAProxy 2.1. Use 'http-response add-header' instead.
The same removal. rspadd is how nearly every pre-2020 guide adds security headers, which is why this is the one people hit while hardening.HAProxy reqadd, rspadd and reqirep were removedhaproxy/src/cfgparse-listen.c

Memcached6

This server is not built with SASL support.
The -S flag was accepted by the parser but the binary was compiled without --enable-sasl. No configuration fixes this; it needs a different build.Require authentication on Memcachedmemcached/memcached.c
ERROR: You cannot allow the ASCII protocol while using SASL.
SASL authentication only exists in the binary protocol, so enabling it forces every client onto binary. A client library speaking ASCII will stop working.Require authentication on Memcachedmemcached/memcached.c
Authfile [/etc/memcached.auth] has a malformed entry. Should be 'user:password'
The -Y auth file wants one user:password pair per line and nothing else — no spaces around the colon, no comments, no blank trailing structure.Require authentication on Memcachedmemcached/memcached.c
ERROR: Cannot enable UDP while using binary SASL authentication.
A hard refusal, not a warning — memcached will not start with both. If you hit this you were re-enabling UDP, which is the thing to reconsider.Memcached UDP is already off — check, don't configurememcached/memcached.c
must add '-u root' to start as root
Memcached was launched by root with no -u flag and refused to continue. It is asking you to either name an unprivileged user or state that you really meant root.Run Memcached as a non-root usermemcached/memcached.c
failed to set rlimit for open files. Try starting as root or requesting smaller maxconns value.
The -c value needs more file descriptors than the process may allocate. Raise LimitNOFILE in the unit file rather than lowering -c blindly, and never solve it by running as root.Set Memcached limits and leave shutdown disabledmemcached/memcached.c

MongoDB1

Access control is not enabled for the database. Read and write access to data and configuration is unrestricted
Logged at startup, under a "startup warnings" tag, whenever the server is running with no authentication configured at all. It is a statement of fact about the running server, not a setup reminder.Enable MongoDB authorizationmongodb/src/mongo/db/startup_warnings_common.cpp

nginx18

nginx: [emerg] invalid value "TLSv1_2" in /etc/nginx/nginx.conf:8
ssl_protocols matches each token literally against a fixed list. The separator is a dot, not an underscore, and the list stops at TLSv1.3 — so a typo and a version that does not exist fail identically.Configure nginx TLS protocols and ciphersnginx/src/core/ngx_conf_file.c
nginx: [emerg] "ssl_protocols" must enable TLSv1.3 for the "listen ... quic" directive in /etc/nginx/nginx.conf:7
HTTP/3 is TLS 1.3 only. A protocol line hardened for HTTP/2 keeps working until a quic listener is added, and then refuses to start — the config did not change, the listener did.Configure nginx TLS protocols and ciphersnginx/src/http/modules/ngx_http_ssl_module.c
nginx: [emerg] invalid parameter "self" in /etc/nginx/nginx.conf:9
The policy was left unquoted, so nginx split it on whitespace and read the third token as add_header's optional parameter — where the only accepted word is `always`. The single quotes around 'self' are consumed by nginx's own config parser, which is why they are missing from the message.Set nginx security headers correctlynginx/src/http/modules/ngx_http_headers_filter_module.c
nginx: [emerg] invalid number of arguments in "add_header" directive in /etc/nginx/nginx.conf:9
The same unquoted-value mistake, but the policy had enough words to push the directive past three arguments. add_header accepts two or three and never more, so a longer policy fails here rather than at the parameter check.Set nginx security headers correctlynginx/src/core/ngx_conf_file.c
nginx: [emerg] unknown directive "includeSubDomains" in /etc/nginx/nginx.conf:12
The semicolon inside the header value ended the add_header line early, so nginx read what followed as a new directive. The whole value has to be quoted — `add_header Strict-Transport-Security "max-age=63072000; includeSubDomains";`.Enable HSTS in nginxnginx/src/core/ngx_conf_file.c
nginx: [emerg] invalid parameter "preload" in /etc/nginx/nginx.conf:12
add_header takes a name, a value and one optional third word, and that word can only be `always`. preload belongs inside the quoted value, not after it.Enable HSTS in nginxnginx/src/http/modules/ngx_http_headers_filter_module.c
nginx: [emerg] a duplicate default server for 0.0.0.0:80 in /etc/nginx/conf.d/site.conf:3
Two server blocks claim default_server on the same address and port. Only one can be the catch-all, and the second copy usually arrived in a vhost file that was pasted rather than edited.Add a default server block in nginxnginx/src/http/ngx_http.c
nginx: [warn] the "user" directive makes sense only if the master process runs with super-user privileges, ignored in /etc/nginx/nginx.conf:1
The master was not started as root, so it cannot drop privileges and the user directive does nothing. Workers simply inherit whoever launched nginx. Note the level — this is a warning, so nginx starts anyway and the config reads as if it worked.Run nginx workers as an unprivileged usernginx/src/core/nginx.c
nginx: [emerg] bind() to 0.0.0.0:80 failed (13: Permission denied)
The other half of the same mistake. Ports below 1024 need privilege at bind time, which is exactly why the master starts as root and only the workers drop down.Run nginx workers as an unprivileged usernginx/src/core/ngx_connection.c
nginx: [warn] "ssl_stapling" ignored, no OCSP responder URL in the certificate "/etc/letsencrypt/live/example.com/fullchain.pem"
The only visible trace that ssl_stapling is doing nothing. The certificate carries no OCSP URL to fetch from, so nginx silently skips stapling and serves the handshake without it.nginx OCSP stapling is mostly obsoletenginx/src/event/ngx_event_openssl_stapling.c
nginx: [emerg] directive "server_tokens" is not terminated by ";" in /etc/nginx/nginx.conf:5
The line is missing its trailing semicolon. Every nginx directive needs one — `server_tokens off` is not valid, `server_tokens off;` is.Hide the nginx version with server_tokensnginx/src/core/ngx_conf_file.c
nginx: [emerg] invalid value "false" in /etc/nginx/nginx.conf:5
The value is not one of the three the directive accepts. It takes off, on or build — not true/false, not 0/1, and not a version string to display.Hide the nginx version with server_tokensnginx/src/core/ngx_conf_file.c
nginx: [emerg] "server_tokens" directive is not allowed here in /etc/nginx/nginx.conf:5
The directive is outside the contexts it is valid in. It belongs in http, server or location — not at the top level of the file, not in events, and not in an if block.Hide the nginx version with server_tokensnginx/src/core/ngx_conf_file.c
limiting requests, excess: 0.607 by zone "one", client: 203.0.113.9, server: example.com, request: "GET /api HTTP/1.1", host: "example.com"
This is limit_req rejecting a request, logged at error level by default. excess is how far past the configured rate the client is, in requests — not bytes, and not a running total.nginx limit_req, limit_conn and limit_ratenginx/src/http/modules/ngx_http_limit_req_module.c
delaying request, excess: 0.304, by zone "one", client: 203.0.113.9, server: example.com, request: "GET /api HTTP/1.1", host: "example.com"
The burst allowance is absorbing the spike instead of rejecting it, so the request is being held rather than dropped. This is what burst without nodelay looks like, and it shows up as latency rather than as 503s.nginx limit_req, limit_conn and limit_ratenginx/src/http/modules/ngx_http_limit_req_module.c
nginx: [emerg] invalid rate "rate=10r/min" in /etc/nginx/nginx.conf:4
limit_req_zone understands r/s and r/m only. There is no r/min and no r/h — the message quotes the whole parameter, including the rate= prefix, which makes it look like the keyword is at fault when the unit is.nginx limit_req, limit_conn and limit_ratenginx/src/http/modules/ngx_http_limit_req_module.c
nginx: [emerg] "alias" directive is not allowed here in /etc/nginx/nginx.conf:8
alias exists only inside a location block. The server-level equivalent is root — which is also the directive that does not carry this traversal footgun.The nginx alias path traversalnginx/src/http/ngx_http_core_module.c
nginx: [emerg] "alias" directive is duplicate, "root" directive was specified earlier in /etc/nginx/nginx.conf:10
Both directives are set on the same location. They are alternatives rather than layers, and seeing both is usually a half-finished migration from one to the other.The nginx alias path traversalnginx/src/http/ngx_http_core_module.c

PostgreSQL2

FATAL: no pg_hba.conf entry for host "10.0.0.7", user "app", database "app", no encryption
No rule matched this connection at all. The last phrase is the connection''s encryption state — "no encryption" means the client arrived in plaintext, so a hostssl rule could never have matched it.Scope pg_hba.conf rules to real clientspostgres/src/backend/libpq/auth.c
FATAL: pg_hba.conf rejects connection for host "10.0.0.7", user "app", database "app", no encryption
A rule did match, and its method is reject. Not the same as the message above — because the first match wins, a broad reject earlier in the file shadows the rule you just added.Scope pg_hba.conf rules to real clientspostgres/src/backend/libpq/auth.c

RabbitMQ9

You've tried to set loopback_users.guest, but there is no setting with that name.
The new-style key was written into an old-style config file, or vice versa. The setting was not applied — so a config intended to restrict guest silently did nothing, which is the dangerous direction for this particular key to fail in.Replace the RabbitMQ guest usercuttlefish (cuttlefish_generator.erl), the config parser RabbitMQ uses
Failed to start TCP listener [::]:5672, error: eaddrinuse
Something already holds the port — usually a previous broker that did not stop cleanly. Note the address: [::] is the wildcard, so a listener you meant to bind to one interface is being started on all of them.Restrict RabbitMQ network listenersrabbitmq/deps/rabbit/src/rabbit_networking.erl
Cookie file /var/lib/rabbitmq/.erlang.cookie must be accessible by owner only
Erlang refuses to start the node because the cookie file's mode is wider than 0400/0600. The message comes from Erlang itself, not RabbitMQ, which is why it isn't in RabbitMQ's documentation — it applies to any Erlang node.Protect the RabbitMQ Erlang cookieerlang/otp lib/kernel/src/auth.erl
Failed to start TLS listener [::]:5671, error: {options,{certfile,"/etc/rabbitmq/certs/cert.pem",{error,enoent}}}
The TLS listener could not start because a file named in the listener options is missing or unreadable by the rabbitmq user. Erlang reports the option that failed and the OS reason, so enoent is a path problem and eacces is a permissions one.Enable TLS for RabbitMQrabbitmq/deps/rabbit/src/rabbit_networking.erl
ACCESS_REFUSED - access to vhost '/' refused for user 'app'
The user authenticated successfully and was then refused the vhost. Credentials are fine; the missing piece is a permissions entry for that user on that vhost, which is a separate step from creating the user.Scope RabbitMQ virtual hosts and permissionsrabbitmq/deps/rabbit/src/rabbit_access_control.erl
ACCESS_REFUSED - write access to exchange 'events' in vhost '/' refused for user 'app'
One of the three permission regexes did not match this resource name. The verb at the front names which — configure, write or read — and the resource is named in full, so this message tells you exactly which regex to widen.Scope RabbitMQ virtual hosts and permissionsrabbitmq/deps/rabbit/src/rabbit_access_control.erl
disk resource limit alarm set on node rabbit@node1.
The broker has blocked every publisher on the node, and the log follows this line with a banner saying so. Consumers keep draining, so the symptom reported is almost always publishers hanging rather than an outage.Set RabbitMQ memory and disk limitsrabbitmq/deps/rabbit/src/rabbit_alarm.erl
Free disk space is insufficient. Free bytes: 48234496. Limit: 50000000
The numbers behind the alarm above. The default limit is an absolute byte figure rather than a percentage, so a large disk can trip it while looking almost empty in df.Set RabbitMQ memory and disk limitsrabbitmq/deps/rabbit/src/rabbit_disk_monitor.erl
Login was refused using authentication mechanism PLAIN. For details see the broker logfile.
What the client is told, and it is vague on purpose — the reason is withheld from the network and written only to the broker log. Read it there rather than trusting what the client reports.RabbitMQ exposed to the internetrabbitmq/deps/rabbit/src/rabbit_reader.erl

Redis and Valkey16

Warning: Could not create server TCP listening socket 10.0.0.5:6379: Cannot assign requested address
The address in the bind line does not exist on this host — usually a config copied between machines, or an interface that comes up after Redis does. Redis logs this per address and carries on to the next one, so a partly-wrong bind line half-works.Bind Redis to a private interfaceredis/src/server.c
Failed listening on port 6379 (tcp), aborting.
The end state when no bind address could be listened on at all. Unlike the warning above this is fatal, which is the good case — a Redis that refuses to start is safer than one that fell back to every interface.Bind Redis to a private interfaceredis/src/server.c
NOAUTH Authentication required.
The server has a password and the client sent none. Worth knowing this is what a correctly configured Redis says to an unauthenticated stranger — its absence on a reachable instance is the finding.Require authentication with Redis ACL usersredis/src/server.c
WRONGPASS invalid username-password pair or user is disabled.
The credential was wrong, or the ACL user exists but is switched off. One message covers both, deliberately, so probing cannot distinguish a bad password from a disabled account.Require authentication with Redis ACL usersredis/src/acl.c
AUTH <password> called without any password configured for the default user. Are you sure your configuration is correct?
A client tried to authenticate against an instance that has no password at all. This is the alarming one — it means the client is better configured than the server.Require authentication with Redis ACL usersredis/src/acl.c
NOPERM User app has no permissions to run the 'config|set' command
The ACL rules denied the command itself. The pipe in the name is a container command and its subcommand, which is how you deny CONFIG SET while leaving CONFIG GET usable.Restrict dangerous Redis commands with ACLsredis/src/acl.c
NOPERM No permissions to access a key
The command was allowed but a key pattern was not. Note it does not name the key — the detailed form exists internally but the wire reply is deliberately vague, so a client cannot enumerate the keyspace through error messages.Restrict dangerous Redis commands with ACLsredis/src/acl.c
No tls-cert-file configured!
TLS was switched on without a certificate. Redis logs this and TLS initialisation fails, rather than silently continuing in plaintext.Enable TLS for Redisredis/src/tls.c
Failed to load certificate: /etc/redis/tls/redis.crt: no start line
OpenSSL could read the file but found no PEM block in it — usually a DER-encoded certificate given a .crt name, or a truncated copy. The trailing text is OpenSSL's own error, not Redis's.Enable TLS for Redisredis/src/tls.c
Failed to configure TLS. Check logs for more info.
The summary line at startup. It is deliberately unhelpful on its own — the actionable message is the one logged just above it.Enable TLS for Redisredis/src/server.c
-DENIED Redis is running in protected mode because protected mode is enabled and no password is set for the default user. In this mode connections are only accepted from the loopback interface.
The instance binds a non-loopback interface and the default user still has no password, so every remote client is refused. Protected mode is reporting the misconfiguration, not causing it.Leave Redis protected-mode onredis/src/networking.c
Failed opening the temp RDB file temp-1234.rdb (in server root dir /var/lib/redis) for saving: Permission denied
The redis user cannot write to its own data directory, which is the normal consequence of having once started Redis as root and left root-owned files behind. The message names the working directory, which is what makes it diagnosable.Run Redis as an unprivileged userredis/src/rdb.c
MISCONF Redis is configured to save RDB snapshots, but it's currently unable to persist to disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.
Every write is now rejected because a background save failed — most often a permissions or disk-space problem on the data directory. Redis is refusing writes on purpose rather than accepting data it cannot persist.Secure the Redis config and data filesredis/src/server.c
Fatal error, can't open config file '/etc/redis/redis.conf': Permission denied
Tightening file modes went one step too far — the redis user must still be able to read its own config. Locking the file to root only stops the server starting.Secure the Redis config and data filesredis/src/config.c
*** FATAL CONFIG FILE ERROR (Redis 8.8.1) ***
The banner printed before the offending line and its content. It goes to stderr rather than the log file, so under systemd it is in journalctl and not in redis.log — which is why it is often reported as starting with no error at all.Secure the Redis config and data filesredis/src/config.c
WARNING: Redis does not require authentication and is not protected by network restrictions. Redis will accept connections from any IP address on any network interface.
Redis stating the exact condition this page is about, at startup, in its own log. There are three variants of this warning and this is the worst one — a narrower wording means either a password or a bind restriction is present.Redis exposed to the internetredis/src/server.c

Only services the site already covers, and only strings that have been verified. The index is built from the corpus rather than maintained separately, so it grows when a control page gains an error and never drifts from what the pages say.