Why am I having KeyError 'val_acc'?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
KeyError: 'val_acc' usually appears when code expects the training history dictionary to contain val_acc, but newer TensorFlow/Keras versions store validation accuracy under val_accuracy. This is a version and metric-name mismatch, not a model-training failure by itself.
The fix is to inspect the keys actually present in history.history and reference metrics dynamically. Hard-coded legacy names from old tutorials often break in modern environments. A small compatibility helper can make plotting and monitoring code robust across versions.
Core Sections
1. Understand where the key comes from
After training, Keras returns a History object:
In current TensorFlow/Keras, common keys include:
lossaccuracyval_lossval_accuracy
Older examples may reference acc and val_acc, causing KeyError when those keys do not exist.
2. Write version-tolerant metric access
Use fallback logic instead of hard-coded names.
This avoids brittle plotting code across environments.
3. Ensure metric is actually configured
If you did not compile with accuracy metrics, validation accuracy keys will never exist.
Then plotting is straightforward:
Also verify callback code, checkpoints, and custom loggers use the same metric names.
Common Pitfalls
- Copying old tutorial code that references
acc/val_accin modern TensorFlow environments. - Forgetting to include
metrics=["accuracy"]duringcompile, so accuracy keys are never logged. - Assuming callback monitor names (
monitor="val_acc") are version-invariant. - Not printing
history.history.keys()before plotting/debugging metric access. - Mixing standalone
kerasandtf.kerasversions, which can produce inconsistent naming behavior.
Summary
KeyError: 'val_acc' is typically a metric key naming mismatch. Inspect actual history keys, use compatibility fallbacks (val_accuracy vs val_acc), and ensure metrics are configured during compile. Once metric names are aligned across training, callbacks, and plotting, the error disappears and logs remain stable across library upgrades.
In team environments, metric naming drift is often introduced by mixed examples, old notebooks, or partial framework upgrades. A good defensive step is to centralize metric key resolution in one utility module and import that everywhere plots, callbacks, and alerts are configured. Then when names change again in future framework versions, you update one place instead of many scripts. This reduces breakage during upgrades and keeps dashboards consistent.
You can also harden training pipelines by validating metric availability immediately after the first epoch. If required keys are missing, fail fast with an explicit message instead of waiting for a later plotting or checkpoint step to throw an opaque KeyError. For example, after fit, compare expected keys against history.history.keys() and raise a custom exception with remediation guidance. This turns a confusing runtime failure into a clear contract check.
For monitoring systems, prefer explicit callback monitor names tied to your resolved metric key. If your compatibility helper decides on val_accuracy, your early stopping and model checkpoint monitors should use the same resolved value. Keeping training metrics, visualization, and callbacks aligned avoids situations where one component silently tracks a different metric than another. Consistency across these layers is what actually eliminates recurring val_acc errors.
A brief post-upgrade checklist can prevent recurrence: print history keys, verify callback monitor names, and run one plotting smoke test in CI. These checks are cheap and catch metric-name drift before training jobs reach production pipelines.
Make this check part of every dependency upgrade branch.

