Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Logstash By James Joyner IV · · 9 min read

Logstash Error Guide: 'dictionary file not found' — Fix a Missing translate dictionary_path

Quick answer

Fix Logstash translate filter 'dictionary file not found': verify dictionary_path, file permissions, YAML/CSV format, and the refresh settings.

  • #logstash
  • #logging
  • #troubleshooting
  • #errors
Free toolkit

Fixing errors like this? Get 500 free DevOps AI prompts

500 copy-paste AI prompts for the stack you actually run — one PDF, free.

Overview

The translate filter enriches events by mapping a source field’s value to a replacement value pulled from an external lookup table — a YAML, JSON, or CSV file referenced by dictionary_path. When Logstash loads (or reloads) the pipeline, the filter reads that file into memory. If the file does not exist, sits at a different path than configured, or the logstash user cannot read it, the plugin aborts pipeline startup and prints a configuration error.

The literal message that appears in /var/log/logstash/logstash-plain.log looks like this:

[ERROR][logstash.filters.translate] Invalid setting for translate filter plugin:

  filter {
    translate {
      # This setting must be a path
      # File does not exist or cannot be opened /etc/logstash/dictionaries/http_codes.yml
      dictionary_path => "/etc/logstash/dictionaries/http_codes.yml"
      ...
    }
  }

The older / dictionary-refresh variant of the same failure reads:

[ERROR][logstash.filters.translate] Can't read dictionary:
{:path=>"/etc/logstash/dictionaries/http_codes.yml", :exception=>"No such file or directory"}

Both mean the same thing: Logstash was told to read a dictionary from disk and the read failed. Because translate validates dictionary_path at plugin registration, the entire pipeline refuses to start rather than silently skipping enrichment.

Symptoms

  • Logstash fails to start, or a specific pipeline stays in a crash-restart loop, right after a config change that added or edited a translate filter.
  • logstash-plain.log shows File does not exist or cannot be opened or Can't read dictionary naming your dictionary_path.
  • bin/logstash --config.test_and_exit fails with a translate plugin configuration error instead of Configuration OK.
  • Events flow but are never enriched — the translate target field is missing — when dictionary refresh silently fails after a hot reload.
  • The pipeline worked in one environment (dev) but not another (prod) where the dictionary file was never deployed.

Common Root Causes

  • The file simply isn’t there — a typo in dictionary_path, or the dictionary was never copied to the host during deployment (baked into a dev image but missing from the prod config-management run).
  • Permissions block the logstash user — the file exists but is owned by root:root with 0600, so the service account that runs logstash gets Permission denied, which surfaces as “cannot be opened.”
  • Relative path resolved from the wrong working directory — a bare dictionary_path => "dicts/codes.yml" is resolved relative to Logstash’s runtime CWD (often /usr/share/logstash), not the config directory.
  • Wrong file extension / format mismatch — the loader picks a parser by extension. A .yaml or .txt file, or a .yml that actually contains CSV, parses as empty or errors out.
  • SELinux or AppArmor denial — the file is present and world-readable but the mandatory-access-control policy forbids logstash from reading outside /etc/logstash.
  • Broken YAML/CSV content — a tab character, unquoted colon, or ragged CSV row makes the dictionary unparseable even though the file opens fine.
  • A symlink target that moveddictionary_path points at a symlink whose destination was rotated or deleted.

Diagnostic Workflow

Start by validating the pipeline in isolation. --config.test_and_exit (aliased -t) parses and registers every plugin without ingesting data, so it reproduces the dictionary read at startup:

sudo -u logstash /usr/share/logstash/bin/logstash \
  -f /etc/logstash/conf.d/enrich-http.conf \
  --path.settings /etc/logstash \
  --config.test_and_exit

Run it as the logstash user (sudo -u logstash) so you exercise the exact permission set the service uses — running as root can mask an EACCES you would hit in production.

Here is a representative pipeline that triggers the error. Logstash .conf files use a Ruby-like DSL, so the config reads like Ruby:

input {
  beats { port => 5044 }
}

filter {
  # Map an HTTP status code in [response][status] to a human label.
  translate {
    source           => "[response][status]"
    target           => "[response][status_label]"
    dictionary_path  => "/etc/logstash/dictionaries/http_codes.yml"
    fallback         => "unknown"
    refresh_interval => 300
    exact            => true
    override         => true
  }
}

output {
  elasticsearch {
    hosts => ["http://localhost:9200"]
    index => "http-access-%{+YYYY.MM.dd}"
  }
}

Now confirm each assumption the filter makes about that file. First, does it exist and can the service account read it:

ls -l /etc/logstash/dictionaries/http_codes.yml
sudo -u logstash cat /etc/logstash/dictionaries/http_codes.yml >/dev/null && echo "readable by logstash"

If ls shows the file but the cat prints Permission denied, it is a permissions problem, not a missing file. Check ownership and the parent-directory execute bits (you need x on every directory in the path to traverse into it):

namei -l /etc/logstash/dictionaries/http_codes.yml

Validate the dictionary content itself. A YAML dictionary must be a flat map of key: value pairs:

# http_codes.yml should look like this:
#   "200": "OK"
#   "404": "Not Found"
#   "500": "Internal Server Error"
ruby -ryaml -e 'p YAML.load_file(ARGV[0])' /etc/logstash/dictionaries/http_codes.yml

If that Ruby one-liner raises a Psych::SyntaxError, the file is present and readable but malformed — fix the YAML, don’t touch the path. Finally, rule out mandatory access control:

sudo ausearch -m avc -ts recent | grep -i logstash   # SELinux denials
sudo dmesg | grep -i 'apparmor.*logstash'             # AppArmor denials

Example Root Cause Analysis

A team added status-code enrichment and it passed CI, but the production pipeline entered a restart loop. logstash-plain.log showed:

[ERROR][logstash.filters.translate] Invalid setting for translate filter plugin:
  # File does not exist or cannot be opened /etc/logstash/dictionaries/http_codes.yml

ls -l /etc/logstash/dictionaries/http_codes.yml returned No such file or directory, which looked like a missing-file problem. But ls -l /etc/logstash/dictionaries/ revealed the file was actually named http-codes.yml (a hyphen), while the config referenced http_codes.yml (an underscore). The dictionary was deployed correctly; the reference had a typo.

The deeper cause was that the developer authored the config on a case-and-punctuation-forgiving local setup where an old copy named http_codes.yml still lingered in the config directory, so --config.test_and_exit passed locally. The prod host, freshly provisioned by config management, only ever had the hyphenated file. The fix was one character — aligning dictionary_path to the deployed filename — plus a guard added to CI: the pipeline lint now runs test_and_exit in a container that mounts only the artifacts config management actually ships, so a stray local file can never make a broken reference pass again.

Prevention Best Practices

  • Deploy dictionaries with the pipeline as one atomic unit (same package, same config-management role), so a config that references a file guarantees the file ships alongside it.
  • Keep every dictionary under /etc/logstash/dictionaries/ owned by root:logstash with mode 0640, and directories 0750, so the service account can read but not write them.
  • Always use absolute dictionary_path values; never rely on Logstash’s runtime working directory.
  • Match extension to content — .yml for YAML, .json for JSON, .csv for CSV — and lint the file in CI before it ever reaches a host.
  • Run --config.test_and_exit as the logstash user in CI so permission and path problems fail the build, not production.
  • Set a sensible fallback so a lookup miss produces a known value instead of an unmapped event, and pin refresh_interval so edits reload without a restart.

Quick Command Reference

# Validate the full pipeline as the service account (reproduces the dictionary read)
sudo -u logstash /usr/share/logstash/bin/logstash \
  -f /etc/logstash/conf.d/enrich-http.conf \
  --path.settings /etc/logstash --config.test_and_exit

# Confirm existence + readability by the logstash user
ls -l /etc/logstash/dictionaries/http_codes.yml
sudo -u logstash test -r /etc/logstash/dictionaries/http_codes.yml && echo readable

# Show every permission bit along the path
namei -l /etc/logstash/dictionaries/http_codes.yml

# Parse-check the dictionary content
ruby -ryaml -e 'p YAML.load_file(ARGV[0])' /etc/logstash/dictionaries/http_codes.yml

# Fix ownership / permissions
sudo chown root:logstash /etc/logstash/dictionaries/http_codes.yml
sudo chmod 0640 /etc/logstash/dictionaries/http_codes.yml

# Watch the log while restarting the service
sudo systemctl restart logstash
sudo tail -f /var/log/logstash/logstash-plain.log

# Check for MAC denials
sudo ausearch -m avc -ts recent | grep -i logstash

Conclusion

dictionary file not found and Can't read dictionary are startup-blocking errors from the translate filter, and they almost always come down to one of three things: the file isn’t where dictionary_path says it is, the logstash user can’t read it, or its contents don’t parse. Reproduce the read with --config.test_and_exit run as the service account, then walk the path with ls, namei -l, and a quick parser check to see exactly which assumption broke. Ship dictionaries atomically with their pipelines, keep them absolute-pathed and correctly owned, and lint them in CI, and this class of error stops reaching production entirely.

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.