{"id":"ecbefb6a927721f3","repo":"redis/redis","slug":"s","errorCode":null,"errorMessage":"%s\n","messagePattern":"%s\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/config.c","lineNumber":651,"sourceCode":"    }\n\n    /* To ensure backward compatibility and work while hz is out of range */\n    if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ;\n    if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ;\n\n    sdsfreesplitres(lines,totlines);\n    reading_config_file = 0;\n    return;\n\nloaderr:\n    if (argv) sdsfreesplitres(argv,argc);\n    fprintf(stderr, \"\\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\\n\",\n        REDIS_VERSION);\n    if (i < totlines) {\n        fprintf(stderr, \"Reading the configuration file, at line %d\\n\", linenum);\n        fprintf(stderr, \">>> '%s'\\n\", lines[i]);\n    }\n    fprintf(stderr, \"%s\\n\", err);\n    exit(1);\n}\n\n/* Load the server configuration from the specified filename.\n * The function appends the additional configuration directives stored\n * in the 'options' string to the config file before loading.\n *\n * Both filename and options can be NULL, in such a case are considered\n * empty. This way loadServerConfig can be used to just load a file or\n * just load a string. */\n#define CONFIG_READ_LEN 1024\nvoid loadServerConfig(char *filename, char config_from_stdin, char *options) {\n    sds config = sdsempty();\n    char buf[CONFIG_READ_LEN+1];\n    FILE *fp;\n    glob_t globbuf;\n\n    /* Load the file content */","sourceCodeStart":633,"sourceCodeEnd":669,"githubUrl":"https://github.com/redis/redis/blob/3acc0c49cf5ad2af9425d333e62728342dd6159b/src/config.c#L633-L669","documentation":"The final fprintf in the loaderr block: prints the human-readable reason string 'err' (a newline-terminated '%s') that was set by whichever parsing/sanity path jumped to loaderr. This is the actionable message (e.g. 'unknown directive', 'wrong number of arguments', 'replicaof directive not allowed in cluster mode') and is followed immediately by exit(1). Without this line the banner and line number alone would not explain the failure.","triggerScenarios":"Printed for every loaderr path: directive-not-found, wrong argument count, invalid enum/numeric value, and the cluster-mode sanity checks at config.c:624-626 and dbnum adjustment. The 'err' pointer is assigned the reason literal just before 'goto loaderr'.","commonSituations":"This is the line operators actually read to fix the problem. Common reasons: 'unknown directive name', 'wrong number of arguments', 'Invalid argument ... for directive ...', and the cluster-mode conflicts. The message text is the authoritative clue when the offending line itself looks syntactically fine.","solutions":["Treat the printed err string as the primary diagnostic and resolve the condition it describes.","Cross-reference the err text with the echoed '>>> ...' line above it to confirm cause and location agree.","If the err mentions cluster mode, remove the conflicting directive (e.g. replicaof) when cluster-enabled yes is set.","Search the Redis source/docs for the exact err string to find the directive's accepted forms."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"#!/usr/bin/env bash\n# Error [22] ('%s') is the human-readable detail string the parser prints after the\n# 'Reading the configuration file' banner. The actionable defense is to validate each\n# directive's arity/value before the server reads it.\nCONF=\"${1:-/etc/redis/redis.conf}\"\n# Minimal arity map for the most commonly mis-set directives.\ndeclare -A ARITY=(\n  [port]=1 [bind]=-1 [save]=-2 [appendonly]=1 [maxmemory]=1\n  [maxmemory-policy]=1 [requirepass]=1 [dir]=1 [dbfilename]=1\n)\nwhile IFS= read -r raw; do\n  line=\"${raw%%#*}\"; line=\"$(echo \"$line\" | xargs)\"\n  [ -z \"$line\" ] && continue\n  set -- $line; d=\"$1\"; shift; argc=$#\n  exp=\"${ARITY[$d]:-}\"\n  if [ -n \"$exp\" ] && [ \"$exp\" -ge 0 ] && [ \"$argc\" -ne \"$exp\" ]; then\n    echo \"directive '$d' expects $exp arg(s), got $argc\" >&2; exit 1\n  fi\ndone < \"$CONF\"","typeGuard":"// Narrow an unknown directive record to a known-good shape before applying it.\nexport type DirectiveName = 'port' | 'bind' | 'save' | 'appendonly' | 'maxmemory' | 'dir' | 'requirepass';\nexport interface ValidDirective { name: DirectiveName; args: readonly string[]; }\nconst KNOWN: Record<DirectiveName, number> = {\n  port: 1, bind: -1, save: -2, appendonly: 1, maxmemory: 1, dir: 1, requirepass: 1,\n};\nexport function isValidDirective(o: unknown): o is ValidDirective {\n  if (typeof o !== 'object' || o === null) return false;\n  const v = o as ValidDirective;\n  if (!Array.isArray(v.args) || !v.args.every(a => typeof a === 'string')) return false;\n  const want = KNOWN[v.name as DirectiveName];\n  if (want === undefined) return false;\n  return want < 0 ? v.args.length >= -want : v.args.length === want;\n}","tryCatchPattern":"// Catch the parser's per-directive failure and present the detail string cleanly.\nfor (const [name, args] of parsedEntries) {\n  try {\n    applyDirective(name, args);\n  } catch (e) {\n    if (e instanceof DirectiveError) {\n      // mirrors the server's '%s' detail line\n      throw new Error(`config directive '${name}': ${e.message}`);\n    }\n    throw e;\n  }\n}","preventionTips":["Maintain an arity/enum table for directives you support and validate against it pre-startup.","Use 'CONFIG GET' after a successful boot to confirm each directive parsed to the value you intended.","For numeric directives (port, timeout, maxmemory) check ranges, not just presence.","Reject unknown directives explicitly in your lint so a typo is never silently ignored.","When templating configs, assert on the rendered output rather than the template."],"tags":["config","diagnostics","redis-server","fatal"],"analyzedSha":"3acc0c49cf5ad2af9425d333e62728342dd6159b","analyzedAt":"2026-08-01T22:07:56.715Z","schemaVersion":2}