# How to Debug Telegraf Plugin Loading and Configuration Issues: A Complete Guide

> Resolve Telegraf plugin loading and configuration issues. Learn to debug plugin registration, parsing, and construction with step-by-step guidance and debug mode insights.

- Repository: [InfluxData/telegraf](https://github.com/influxdata/telegraf)
- Tags: how-to-guide
- Published: 2026-05-14

---

**Enable agent debug mode with `debug = true` in the `[agent]` section and run `telegraf --config telegraf.conf --debug` to trace the registration, parsing, and construction phases while monitoring [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) for field-miss tracking and plugin factory lookups.**

Debugging Telegraf plugin loading and configuration issues requires understanding how the `influxdata/telegraf` repository discovers and instantiates plugins from TOML configuration. The initialization process involves three distinct phases—registration, parsing, and construction—each of which can fail silently or emit cryptic errors without proper diagnostic flags. By instrumenting the **agent debug mode** and inspecting specific files like [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go), you can isolate whether failures occur during factory registration, AST parsing, or runtime wiring.

## Understanding the Three Phases of Plugin Initialization

Telegraf discovers, loads, and configures plugins (inputs, processors, aggregators, outputs, secret-stores, and parsers) through a rigid three-phase pipeline implemented in the core configuration engine.

### Phase 1: Plugin Registration via init()

Each plugin package registers a **factory function** in a global map during package initialization. These maps—`inputs.Inputs`, `processors.Processors`, `outputs.Outputs`, and others—are populated inside `init()` blocks when the binary starts.

For example, in [`plugins/inputs/cpu/cpu.go`](https://github.com/influxdata/telegraf/blob/main/plugins/inputs/cpu/cpu.go), the CPU input registers itself with:

```go
inputs.Add("cpu", func() telegraf.Input {
    return &CPUStats{}
})

```

This pattern applies to every built-in plugin and any custom plugins compiled into the Telegraf binary. If the `init()` function does not execute, the factory remains absent from the global map, causing "undefined plugin" errors later.

### Phase 2: TOML Configuration Parsing

When you run `telegraf --config telegraf.conf`, the entry point calls `config.Config.LoadConfig` (defined in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go)), which chains to `LoadConfigData` and finally `parseConfig`. This sequence:

1. Builds an Abstract Syntax Tree (AST) using `github.com/influxdata/toml/ast.Table`.
2. Walks each top-level key (`agent`, `inputs`, `outputs`, `processors`, etc.).
3. Looks up the plugin name in the registration map (e.g., `inputs.Inputs[name]`) to retrieve the factory function.

If the TOML contains syntax errors, Telegraf aborts here before any plugin instantiation occurs.

### Phase 3: Plugin Construction and Wiring

The helper methods `addInput`, `addOutput`, `addProcessor`, `addAggregator`, and `addSecretStore` (all in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go)) perform the final assembly:

- **Label selection**: Evaluates optional `label` filters (`InputFilters`, `OutputFilters`, etc.) via `matchesLabelSelection`.
- **Parser/serializer wiring**: If a plugin implements `ParserPlugin` or `SerializerPlugin`, the methods `addParser` and `addSerializer` attach the appropriate codec.
- **Field-miss tracking**: A local counter records TOML fields not consumed during unmarshalling; excessive misses trigger configuration errors.
- **TLS validation**: For outputs exposing `TLSConfig()`, the method validates certificates and TLS settings.
- **Secret linking**: After all plugins instantiate, `LinkSecrets` resolves references like `${INFLUX_TOKEN}` against secret-stores.

## Enabling Verbose Debugging Mode

The most direct way to debug Telegraf plugin loading and configuration issues is to enable **agent debug mode**.

Add this to your configuration file:

```toml
[agent]
debug = true

```

When `debug` is `true`, Telegraf logs every loading step, including:
- "Loading config: …" emitted by `LoadConfig`.
- "I! Plugin … added" printed by the `add*` functions after successful unmarshalling.
- Warnings for unknown fields, TLS errors, or deprecation notices.

Alternatively, enable debugging temporarily from the command line without modifying the config:

```bash
telegraf --config telegraf.conf --debug

```

For maximum verbosity including stack traces, set the logger to the `trace` level:

```toml
[agent]
logformat = "structured"
logtarget = "stderr"
debug = true

```

## Diagnosing Common Plugin Loading Failures

When a plugin fails to load, Telegraf emits specific error messages originating from distinct locations in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go):

| Situation | Error Message | Origin |
|-----------|---------------|--------|
| **Unknown plugin name** | `undefined but requested input: xyz` | `addInput`, `addOutput`, etc., when the name is absent from the registration map. |
| **Missing required fields** | `line X: configuration specified the fields "foo", but they were not used` | `c.missingTomlField` tracking unused TOML keys after unmarshalling. |
| **TLS mis-configuration** | Errors returned from `TLSConfig()` validation | `addOutput` when TLS certificate checks fail. |
| **Deprecated plugin** | `plugin deprecated` notice | `printHistoricPluginDeprecationNotice` checking `inputs.Deprecations` or `outputs.Deprecations` maps. |
| **Secret-store missing** | `unknown secret-store` | `LinkSecrets` when a `${secret:store:id}` reference cannot be resolved. |

## Step-by-Step Debugging Workflow

Follow this systematic approach to isolate plugin loading failures:

1. **Verify registration**: Confirm the plugin's `init()` runs by executing `go test ./... -run TestPluginRegistered` in the plugin's package. If the test fails, the plugin is not compiled into the binary.

2. **Validate TOML syntax**: Use `toml-lint` or run `telegraf --config /dev/null` to isolate syntax errors that prevent parsing from reaching the plugin initialization phase.

3. **Inspect the parsed AST**: Temporarily insert `log.Printf("%#v", tbl)` after the `parseConfig` call in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) to view the exact structure Telegraf received from the TOML parser.

4. **Confirm filter lists**: If using `namepass`/`namedrop` or the `--input-filter` flag, ensure the target plugin name matches exactly (case-sensitive) against the registered name.

5. **Locate unused fields**: Check the line number in "field not used" errors. The error message cites the specific line in the original file (e.g., `line 27`) where Telegraf detected unconsumed configuration keys.

6. **Check TLS certificates**: For outputs requiring TLS (e.g., `outputs.influxdb_v2`), verify certificate file paths and set `insecure_skip_verify = true` temporarily to rule out certificate validation issues.

7. **Validate secret references**: Ensure secret-store IDs in `${secret:store:id}` syntax match defined stores exactly; missing definitions cause `LinkSecrets` to fail after plugin construction.

## Practical Debugging Examples

### Minimal Config with Debug Enabled

Create [`telegraf.conf`](https://github.com/influxdata/telegraf/blob/main/telegraf.conf):

```toml
[agent]
debug = true
interval = "10s"

[[inputs.cpu]]
  percpu = true
  totalcpu = true
  collect_cpu_time = true

[[outputs.influxdb]]
  urls = ["http://localhost:8086"]
  database = "telegraf"

```

Run with:

```bash
telegraf --config ./telegraf.conf

```

Expected debug output:

```

I! Loading config: ./telegraf.conf
I! Adding input cpu
I! Adding output influxdb
D! Input cpu initialized
D! Output influxdb initialized

```

### Verifying Custom Plugin Registration

For a custom plugin compiled into the binary:

```go
// myplugin.go
package myplugin

import (
    "github.com/influxdata/telegraf"
    "github.com/influxdata/telegraf/plugins/inputs"
)

type MyPlugin struct{}

func (p *MyPlugin) SampleConfig() string { return "" }
func (p *MyPlugin) Gather(acc telegraf.Accumulator) error { return nil }

func init() {
    inputs.Add("myplugin", func() telegraf.Input { return &MyPlugin{} })
}

```

After building:

```bash
go build -o telegraf ./cmd/telegraf
go tool nm telegraf | grep myplugin

```

If the symbol appears, registration succeeded. If not, the package import is missing from your build.

### Detecting Configuration Field Errors

Given this config:

```toml
[[inputs.cpu]]
  unknown_option = true

```

Telegraf outputs:

```

E! line 2: configuration specified the fields "unknown_option", but they were not used; this is either a typo or this config option does not exist in this version

```

The line number points directly to the offending key in [`plugins/inputs/cpu/cpu.go`](https://github.com/influxdata/telegraf/blob/main/plugins/inputs/cpu/cpu.go) or your custom TOML.

## Summary

- **Plugin registration** occurs in `init()` blocks using `inputs.Add` and similar functions; verify with `go test` or `go tool nm`.
- **Configuration parsing** happens in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) via `LoadConfig` → `parseConfig`, building an AST that must match registered plugin names.
- **Construction and wiring** uses `addInput`, `addOutput`, and related methods to handle labels, parsers, TLS, and secret resolution.
- **Enable `debug = true`** in the `[agent]` section or use `--debug` to trace the exact phase where loading fails.
- **Field-miss tracking** in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) catches typos by reporting unused TOML fields with specific line numbers.

## Frequently Asked Questions

### How do I know if a plugin is registered correctly?

Run `go test ./... -run TestPluginRegistered` within the plugin's directory to verify the `init()` function executed. Alternatively, after building Telegraf, use `go tool nm telegraf | grep <plugin_name>` to confirm the registration symbol exists in the binary; if absent, the plugin package is not imported in your build.

### Why does Telegraf say a field is not used?

This error originates from the field-miss counter in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go). After unmarshalling TOML into a plugin struct, Telegraf compares consumed fields against the AST; any field present in the config but absent from the struct (or misspelled) increments the miss count. The error cites the exact line number where the unused field appears.

### How can I see the exact config structure Telegraf parses?

Insert a temporary debug line after the `parseConfig` function in [`config/config.go`](https://github.com/influxdata/telegraf/blob/main/config/config.go) to print the AST table: `log.Printf("%#v", tbl)`. This outputs the raw structure derived from your TOML, revealing plugin names, nested tables, and key-value pairs exactly as the parser interpreted them.

### What causes "undefined but requested input" errors?

This message emits from `addInput`, `addOutput`, or similar methods when the plugin name specified in your TOML does not exist in the global registration map (e.g., `inputs.Inputs`). Causes include typos in the plugin name, missing imports for custom plugins, or attempting to use a plugin excluded from your specific Telegraf build.