Skip to main content

Elasticsearch

Observability

Synopsis

Creates an Elasticsearch target that sends data using the Bulk API. Supports multiple endpoints, field normalization, customizable batch sizing, and automatic load balancing across Elasticsearch nodes.

Schema

- name: <string>
description: <string>
type: elastic
status: <boolean>
pipelines: <pipeline[]>
properties:
version: <numeric>
index: <string>
max_payload_size_kb: <numeric>
batch_size: <numeric>
timeout: <numeric>
insecure_skip_verify: <boolean>
ca_name: <string>
server_name: <string>
cert_name: <string>
key_name: <string>
passphrase: <string>
min_tls_version: <string>
max_tls_version: <string>
use_compression: <boolean>
write_action: <string>
filter_path: <string>
pipeline: <string>
field_format: <string>
endpoints:
- endpoint: <string>
username: <string>
password: <string>
debug:
status: <boolean>
dont_send_logs: <boolean>

Configuration

The following are the fields used to define the target:

FieldRequiredDefaultDescription
nameY-Target name
descriptionN-Optional description
typeY-Must be elastic
pipelinesN-Optional post-processor pipelines
statusNtrueEnable/disable the target

Elasticsearch

FieldRequiredDefaultDescription
versionNautoAccepted but not applied. The value is stored and never read, so no version detection or version-specific behavior follows from it
indexY-Default Elasticsearch index name
max_payload_size_kbN4096Maximum bulk request size in KB
batch_sizeN10000Maximum number of events per batch
timeoutN30Connection timeout in seconds
use_compressionNtrueEnable GZIP compression
write_actionNcreateBulk API action (index, create, update, delete)
filter_pathNerrors,items.*.error,items.*._index,items.*.statusResponse filter path
pipelineN-Ingest pipeline name
field_formatN-Data normalization format. See applicable Normalization section

Endpoint

FieldRequiredDefaultDescription
endpointY-Elasticsearch URL (automatically appends /_bulk if not present)
usernameN-Basic auth username
passwordN-Basic auth password

TLS

TLS is engaged by the endpoint URL scheme: an https:// endpoint enables it, an http:// endpoint does not. There is no status field. The fields below are top-level, at the root of properties.

The web interface exposes only insecure_skip_verify for these targets. Every other field below — the CA bundle, the client certificate and key, the SNI override and the version bounds — has to be set in the YAML configuration or through the API; there is no form control for it.

FieldRequiredDefaultDescription
insecure_skip_verifyNfalseSkip server certificate verification. Use only for testing.
ca_nameN-CA bundle used to verify the server certificate. When unset, the host trust store is used; when set, it replaces the host trust store rather than adding to it.
server_nameN-SNI hostname override for the TLS handshake
cert_nameN*-Client certificate for mutual TLS
key_nameN*-Client private key for mutual TLS
passphraseN-Passphrase for an encrypted private key
min_tls_versionNtls1.2Minimum accepted TLS version (tls1.0, tls1.1, tls1.2, tls1.3)
max_tls_versionNtls1.3Maximum accepted TLS version (tls1.0, tls1.1, tls1.2, tls1.3)

* = Mutual TLS requires both cert_name and key_name. Setting only one is a configuration error.

note

A nested tls: block is also accepted, and a non-empty one replaces the flat shape rather than merging with it: the sender reads the block and ignores every flat key, including options the block leaves out. Use one shape or the other, never a mixture.

insecure_skip_verify is the single exception. It is read from the nested block when present and otherwise falls back to the root, so a target carrying a hand-written tls: block keeps the skip-verify its form wrote. Only an absent nested value falls through — a nested false is an explicit statement and overrides a root true.

There is no tls.status: TLS is off when the whole block is absent, and a status key inside the block is not read.

note

TLS material fields (cert_name, key_name, ca_name, client_ca_name) accept any of the following:

  • File name — resolved relative to the service root directory. Nested paths such as certs/prod/server.pem are supported.
  • Absolute path — honored only if it resolves inside the service root. Any path that escapes the root is refused.
  • Inline PEM content — used verbatim when the value contains -----BEGIN.
  • Environment variable${ENV_VAR}.
  • Vault reference$secret{id=...} or $secret{store=...,ref=...}.

Scheduling

See Scheduling and Pool Behavior for interval and cron fields shared by all targets.

Debug Options

FieldRequiredDefaultDescription
debug.statusNfalseEnable debug logging
debug.dont_send_logsNfalseProcess logs but don't send to target (testing)

Details

The target supports multiple endpoints, authentication, compression, and ingest pipelines. Data is batched for efficient delivery and can be automatically routed to different indices.

URLs are automatically appended with /_bulk if the suffix is not present. Events are batched until either the batch size or payload size limit is reached.

For load balancing, events are sent to randomly selected endpoints. If an endpoint fails, the next endpoint in the randomized list is tried until successful delivery or all endpoints fail.

Each event is automatically enriched with a timestamp in RFC3339 format based on the log's epoch time. You can route events to different indices by setting the index field in a pipeline processor.

warning

Long timeout values may lead to connection pooling issues and increased resource consumption.

warning

Setting max_payload_size_kb too high might cause memory pressure and can exceed Elasticsearch's http.max_content_length setting (default 100MB).

Load Balancing and Failover

When multiple endpoints are configured, the target uses randomized load balancing. For each batch:

  1. Endpoints are randomly shuffled
  2. The batch is sent to the first endpoint
  3. If it fails, the next endpoint in the shuffled list is tried
  4. This continues until successful delivery or all endpoints fail

If only some endpoints fail but delivery eventually succeeds, the batch is cleared and a partial error is logged. If all endpoints fail, the batch is retained for retry and a complete failure error is returned.

JSON Message Handling

The target intelligently handles messages that are already in JSON format:

  • If a message contains the text @timestamp anywhere, or is ECS-normalized, it's treated as a structured JSON document
  • The JSON is parsed and sent as-is to Elasticsearch
  • If parsing fails, the record is not sent. Delivery fails with failed to parse JSON message and the payload is retried. There is no plain-text fallback for these records
  • Any other message is wrapped into a JSON document with its text, a timestamp, and the destination index

This allows you to send both structured and unstructured logs through the same target, as long as plain text does not mention @timestamp.

Dynamic Index Routing

Route events to different indices using pipeline processors by setting the index field:

pipelines:
- name: route_by_type
processors:
- set:
field: index
value: "error-logs"
if: "level == 'error'"
- set:
field: index
value: "metrics"
if: "type == 'metric'"

This allows flexible routing without creating multiple target configurations.

Bulk API Error Handling

The target parses the bulk API response to detect individual document errors:

  • Uses filter_path to reduce response size and focus on error details
  • Extracts error type, reason, and HTTP status for failed documents
  • Returns detailed error messages indicating which documents failed and why

Common errors include:

  • Document version conflicts (for create action)
  • Mapping errors (field type mismatches)
  • Index not found or closed
  • Pipeline failures (when using ingest pipelines)

Write Actions

The write_action field determines how documents are indexed:

  • create (default): Only index if document doesn't exist. Fails on duplicates.
  • index: Index or replace existing document. Always succeeds unless there's a system error.
  • update: Update existing document. Fails if document doesn't exist.
  • delete: Remove document. Use carefully.

Response Filtering

The filter_path parameter filters the bulk API response to reduce network overhead:

  • errors: Boolean indicating if any operations failed
  • items.*.error: Error details for failed operations
  • items.*._index: Index name for each operation
  • items.*.status: HTTP status code for each operation

For high-volume scenarios, this filtering significantly reduces response size and parsing overhead.

Field Normalization

The field_format property allows normalizing log data to standard formats:

  • ecs - Elastic Common Schema

Field normalization is applied before the logs are sent to Elasticsearch, ensuring consistent indexing and search capabilities. ECS normalization maps common fields to Elasticsearch's standard schema for improved compatibility with Kibana dashboards and detection rules.

Compression

Compression is enabled by default and uses gzip to reduce network bandwidth. This adds minimal CPU overhead but can significantly improve throughput for high-volume scenarios. Disable compression only if you have bandwidth to spare and want to reduce CPU usage.

Examples

Basic

Simple Elasticsearch output with a single endpoint...

targets:
- name: elastic_output
type: elastic
properties:
index: "logs-%Y.%m.%d"
endpoints:
- endpoint: "http://elasticsearch:9200"

Secure

Secure configuration with authentication and TLS...

targets:
- name: secure_elastic
type: elastic
properties:
index: "secure-logs"
use_compression: true
endpoints:
- endpoint: "https://elasticsearch:9200"
username: "elastic"
password: "password"
insecure_skip_verify: false
warning

In production environments, setting insecure_skip_verify to true is not recommended.

Ingest Pipeline

Send data through an ingest pipeline for server-side processing...

targets:
- name: pipeline_elastic
type: elastic
properties:
index: "processed-logs"
pipeline: "log-processor"
write_action: "create"
endpoints:
- endpoint: "http://elasticsearch:9200"

High-Volume

Optimized for high-volume data ingestion with load balancing...

targets:
- name: highvol_elastic
type: elastic
properties:
index: "metrics"
batch_size: 20000
max_payload_size_kb: 8192
use_compression: true
timeout: 60
endpoints:
- endpoint: "http://es1:9200"
- endpoint: "http://es2:9200"
- endpoint: "http://es3:9200"

Field Normalization

Using ECS field normalization for enhanced compatibility with Elastic Stack...

targets:
- name: ecs_elastic
type: elastic
properties:
index: "normalized-logs"
field_format: "ecs"
endpoints:
- endpoint: "http://elasticsearch:9200"

Index Action

Using index action to allow document updates and overwrites...

targets:
- name: index_elastic
type: elastic
properties:
index: "application-logs"
write_action: "index"
endpoints:
- endpoint: "http://elasticsearch:9200"

Minimal Response

Optimize for minimal response size by filtering to only errors...

targets:
- name: minimal_elastic
type: elastic
properties:
index: "logs"
filter_path: "errors"
endpoints:
- endpoint: "http://elasticsearch:9200"

Performance Tuning

Batch Size vs Payload Size

Events are batched until either limit is reached:

  • batch_size: Number of events per batch
  • max_payload_size_kb: Total size in kilobytes

Tune these based on your average event size:

  • Small events (<1KB>): Increase batch_size, keep default max_payload_size_kb
  • Large events (>10KB): Keep default batch_size, increase max_payload_size_kb
  • Mixed sizes: Monitor both limits and adjust based on actual batch sizes

Timeout

Setting appropriate timeouts helps balance reliability and performance:

  • Short timeouts (10-30s): Fail fast, better for real-time scenarios
  • Long timeouts (60s+): More tolerant of network issues, but may cause connection pooling problems

Compression

Enable compression (default) for high-volume scenarios to reduce network bandwidth. Disable only if CPU is constrained and network bandwidth is abundant.

Filter Path

The default filter_path provides detailed error information while minimizing response size. For even better performance in high-volume scenarios with low error rates, use filter_path: "errors" to only return the error flag.

Troubleshooting

This section covers the errors you are most likely to see with the elastic target, what causes each one, and how to fix it. The same implementation serves the amazonopensearch and elasticsecurity targets, documented on their own pages as Amazon OpenSearch and Elastic Security, so everything here applies to them as well. Where Amazon OpenSearch differs, because it signs requests with AWS IAM instead of sending a user and password, the entry says so.

Where to look:

  • Director logs. Target errors are tagged with the target name and carry "Section":"SenderPool". The part after Reason: or after the last colon is the actual cause. Everything up to from Elastic: is written by Director, and what follows it is the cluster's own answer.
  • The target's connection status in the web interface. It shows the same reason as the log line.

See Target Delivery Errors for how Director logs and retries target failures.

Which permission or setting is missing?

No permission is checked while the target starts. Director resolves the credentials, builds one HTTP client per endpoint, and reports the target as connected without calling the cluster once. The first proof that a credential or a privilege works is the first batch, so permission problems always arrive as delivery errors and never as startup errors. Match the error you see against this table.

Error textWhat it needsMust be granted on
received status code 401 from Elastic: with a security_exception body (typical)username and password both filled in, for a cluster user that is enabledEvery entry under endpoints. Credentials are per endpoint, not per target
received status code 403 from Elastic: naming indices:data/write/bulk (typical)The index privilege create_doc for the default write_action: create, or index, write or create for write_action: indexEvery index or data stream the target writes to, including every value a pipeline puts in the index field
A per-item failure whose type is typically index_not_found_exceptionThe auto_configure or create_index index privilege, and a cluster action.auto_create_index setting that allows the nameOnly when the index or data stream does not already exist. The target never creates one
A per-item failure naming the id in pipeline (typical)The ingest pipeline has to exist on the cluster. No extra privilege is needed for itOnly when pipeline is set
received status code 403 from Elastic: naming es:ESHttpPost (typical)The IAM action es:ESHttpPostarn:aws:es:<region>:<account>:domain/<domain name>/*, for the identity the target signs with, on amazonopensearch with use_iam: true
failed to sign request: failed to retrieve AWS credentials:Both key and secret, or an instance or task role on the Director hostamazonopensearch with use_iam: true

username and password are the only user credentials the target sends. Elastic API keys, Cloud IDs and bearer tokens are not accepted, so basic authentication, or AWS IAM on Amazon OpenSearch, are the two ways to authenticate. No cluster-level privilege is required. The target only posts to /_bulk and never reads cluster or version information, so monitor, manage and read actions can all be left out. On Amazon OpenSearch with fine-grained access control, the IAM action alone is not enough either: the domain access policy has to allow the same principal, and the IAM identity has to be mapped to an OpenSearch role that may write to the index.

warning

OpenSearch Serverless collections are not supported. Requests are always signed for the es service, and a Serverless collection expects aoss, so it refuses every batch with a 403 whose body typically complains about the service name. Send to a managed OpenSearch domain instead.

"received status code 401 from Elastic"

[Error] [director] [target-<target id>] [elastic_output] Sender worker 2 execute() failed for elastic_output: target broken: failed to finalize target cache: endpoint https://elasticsearch.example.com:9200/_bulk: received status code 401 from Elastic: ...; all endpoints failed

Cause: the cluster rejected the credentials. The body after from Elastic: is the cluster's own answer, and for a 401 it typically carries a security_exception with wording like unable to authenticate user, or missing authentication credentials for REST request. The second wording is the trap: the authentication header is only sent when username and password both hold a value, so leaving either one empty sends the batch anonymously and the cluster reports credentials as missing even though a user is configured.

Fix: set both fields on every entry under endpoints, and confirm the user is enabled on the cluster. If a value comes from ${VAR} or $secret{...}, check that it resolves to something non-empty. On Amazon OpenSearch with use_iam: false, the internal user has to exist in the domain's own user database. No data is lost: a 401 is never given up on, so the payload stays queued and is retried every few seconds until the credentials work.

"received status code 403 from Elastic"

[Error] [director] [target-<target id>] [elastic_output] Sender worker 1 execute() failed for elastic_output: target broken: failed to finalize target cache: endpoint https://elasticsearch.example.com:9200/_bulk: received status code 403 from Elastic: ...; all endpoints failed

Cause: the credentials were accepted but the write was not allowed. The body tells you which of two forms you have.

  • On Elasticsearch, it typically names a security_exception, the action indices:data/write/bulk, the user, and the index it refused, along with the privileges that would have granted it.
  • On Amazon OpenSearch with IAM, it typically names the signing identity and is not authorized to perform: es:ESHttpPost. A body that complains about the signature, the region, or an expired token means the request was signed wrongly rather than blocked by a policy.

Fix:

  1. On Elasticsearch, grant the index privilege from the table above on every index pattern the target writes to, then wait for the next retry.
  2. On Amazon OpenSearch, grant es:ESHttpPost on the domain ARN, allow the same principal in the domain access policy, and map the IAM identity to a writing role if fine-grained access control is on.
  3. For a signature complaint, check that secret is the one that belongs to key, and that region is the domain's own region.
  4. For an expired token, replace session. A signature that worked yesterday and fails today typically means the Director host clock has drifted, so check NTP on the host.

No data is lost, and the batch is retried until the permission is in place.

"bulk operation had errors" with a document the index refuses

The cluster can accept the request and still refuse individual documents. Those failures are reported per item, one segment per document, typically like this:

[Error] [director] [target-<target id>] [elastic_output] Sender worker 1 Finalize failed on flush for target "elastic_output": endpoint https://elasticsearch.example.com:9200/_bulk: record rejected by target: bulk operation had errors: item 0 (create on app-logs): status 400, type=..., reason=...

Cause: each segment gives the document's position in the batch, the action and index it was sent to, the status the cluster gave it, and the cluster's own type and reason. With status 400 the type is typically document_parsing_exception, mapper_parsing_exception or strict_dynamic_mapping_exception, and the reason typically names the field and the mapped type it could not be parsed into. An illegal_argument_exception covers the rest: a data stream that only accepts create, an ingest pipeline that does not exist, or a field-count limit that has been reached.

Fix: read the type and reason of the first item, then fix the source of the mismatch.

  1. Correct the index mapping or template, or normalize the field in a Director pipeline with convert, remove, or field_format: ecs.
  2. Set write_action: create when the destination is a data stream. A data stream refuses index.
  3. Create the ingest pipeline named in pipeline on the cluster, or remove the setting.
  4. Check write_action for typos. The value is not validated, so an unknown action makes the cluster refuse the whole batch with a 400.
warning

This is where data is lost. The rejection is treated as deterministic, so the payload is delivered four times and then given up on, logged as dropping <payload> for target "elastic_output" after 4 rejected flush attempts. The whole payload goes, not only the refused documents, so records the index would have accepted are lost with them. Fix the mapping before the fourth delivery, or the batch is gone.

Expect duplicates as well. Chunks that were accepted earlier in the same flush are sent again on each of the four deliveries, and with create and no document id the cluster generates a new id every time.

"single event at index ... exceeds hard limit", or status 413

Two size limits produce two different errors. One document larger than max_payload_size_kb is refused before the cluster is contacted:

[Error] [director] [target-<target id>] [elastic_output] Sender worker 4 Finalize failed on flush for target "elastic_output": endpoint https://elasticsearch.example.com:9200/_bulk: record rejected by target: single event at index 37 size 4318221 bytes exceeds hard limit of 4096 KB

A batch that is too large for the cluster is refused by the cluster, typically with an empty body:

[Error] [director] [target-<target id>] [elastic_output] Sender worker 4 Finalize failed on flush for target "elastic_output": endpoint https://elasticsearch.example.com:9200/_bulk: record rejected by target: received status code 413 from Elastic:

Cause: batches are cut into chunks at 90 percent of max_payload_size_kb, measured before compression, so the default of 4096 produces chunks of about 3.6 MB. A single document above the full max_payload_size_kb fits into no chunk at all and gives the first error. A 413 means the chunk was still too large for the cluster's http.max_content_length, or for a proxy in front of it.

Fix: for the first error, raise max_payload_size_kb above the size the message reports, or trim the record in a pipeline before it reaches the target. For the 413, lower max_payload_size_kb under the limit the cluster or the proxy enforces, or raise that limit. Both wrap the same rejection as the entry above, so both lose the payload after four deliveries. Treat a 413 as urgent.

"received status code 429 from Elastic", or per-item throttling

[Error] [director] [target-<target id>] [elastic_output] Sender worker 6 execute() failed for elastic_output: target broken: failed to finalize target cache: endpoint https://elasticsearch.example.com:9200/_bulk: received status code 429 from Elastic: ...; all endpoints failed

Cause: the cluster is pushing back on the write rate. The body typically names an es_rejected_execution_exception. The same back-pressure can also arrive per document, as status 429 segments inside a bulk operation had errors message, when only part of the batch was refused.

Fix: send less per request and spread the requests out. Lower batch_size, lower max_payload_size_kb, or give the target an interval or cron so it flushes on a schedule instead of after every payload. See Scheduling and Pool Behavior. Adding indexing capacity on the cluster side addresses the cause rather than the symptom.

No data is lost, and the batch is retried until the cluster accepts it. The target has no rate limiting of its own and does not read a Retry-After header, so a throttled batch comes back every few seconds. When only some documents in a chunk were refused, the whole chunk is sent again, so the accepted ones are indexed twice.

"no such host", "connection refused", or a certificate error

A transport failure is reported with the request URL and then the network stack's own message. A name that does not resolve typically reads like this:

[Error] [director] [target-<target id>] [elastic_output] Sender worker 3 execute() failed for elastic_output: target broken: failed to finalize target cache: endpoint https://elasticsearch.example.com:9200/_bulk: Post "https://elasticsearch.example.com:9200/_bulk?filter_path=...": dial tcp: lookup elasticsearch.example.com: no such host; all endpoints failed

Cause: the tail of the line says which step failed. The wording comes from the network stack, so it varies, but these are the ones you will meet.

Text in the tailWhat it meansWhat to change
no such hostThe endpoint hostname does not resolve from the Director hostFix the name in endpoint, or the host's DNS
connection refused or i/o timeoutWrong port, a firewall in the way, or the node is downOpen the port, or correct endpoint
context deadline exceededThe cluster did not answer within timeout, 30 seconds by defaultRaise timeout, or lower batch_size so each request is smaller
x509: certificate signed by unknown authorityThe cluster presents a certificate from a private CASet ca_name to that CA. Use insecure_skip_verify: true only while testing
certificate is valid for another nameThe certificate does not cover the name or address in endpointSet server_name to the name on the certificate
tls: bad certificateThe cluster wants a client certificateSet cert_name and key_name, and passphrase if the key is encrypted
server gave HTTP response to HTTPS clientendpoint uses https:// against a plain HTTP portCorrect the scheme or the port
proxyconnect tcp:The proxy in HTTPS_PROXY refused the connection or could not be reachedFix the proxy, or add the host to NO_PROXY for the Director service
first path segment in URL cannot contain colonendpoint has no scheme, for example elasticsearch.example.com:9200Write the full URL, https://elasticsearch.example.com:9200

A 404 belongs here too. /_bulk is appended to whatever endpoint holds, so a Kibana or OpenSearch Dashboards URL produces a 404 whose body typically says that no handler was found for the path. Point endpoint at the search REST root, not at the user interface in front of it.

Fix: correct the setting named above, then wait for the next attempt. No data is lost while this lasts. When several endpoints are configured, each reason is listed as its own endpoint <url>: <reason> segment and the line ends with all endpoints failed, so read the segments separately. They can fail for different reasons.

"partial endpoint failed"

[Warning] [director] [target-<target id>] [elastic_output] One or more endpoints have failed during finalization of elastic_output target logs. Error: endpoint https://elasticsearch.example.com:9200/_bulk: Post "https://elasticsearch.example.com:9200/_bulk?filter_path=...": dial tcp 10.0.1.5:9200: connect: connection refused
partial endpoint failed

Cause: one endpoint failed and another accepted the data. Endpoints are shuffled for each batch and tried in that order, so this is the normal face of a single unhealthy node. The message is a warning, not an error, and it names the endpoint that failed.

Fix: check the named node. Nothing needs to change in the target, and the warning stops when the node recovers or is removed from endpoints. The data was delivered. When an endpoint fails part way through a batch, only the part that was not sent yet goes to the next endpoint, so failover does not duplicate documents across endpoints.

"failed to parse bulk response"

[Error] [director] [target-<target id>] [elastic_output] Sender worker 3 execute() failed for elastic_output: target broken: failed to finalize target cache: endpoint https://elasticsearch.example.com:9200/_bulk: failed to parse bulk response: ...; all endpoints failed

Cause: Director reads a bounded amount of the bulk response, at least 1 MB and more for large chunks. When every document in a chunk is refused and the cluster's reasons are long, the answer outgrows that bound and the copy that is parsed ends mid-document. The log can then only report that the response did not parse. It cannot show the per-item reasons, because they sit past the point where the copy ends. This is a limit of how much of the answer the log can carry, not a fault on the cluster.

Fix: get the reason from the cluster instead.

  1. Lower batch_size, to 500 for example. Fewer documents per chunk means fewer reasons in the answer, and the next attempt usually reports them as a normal bulk operation had errors message.
  2. Send a handful of the same records to the same index by hand, with the same write_action and pipeline, and read the per-item reason the cluster returns.
  3. Compare the fields your pipeline emits against the current mapping of the destination index. A mapping or template change is the usual trigger for a chunk where every document fails at once.
  4. Look up the same index and period in the cluster's own logs.

The same message also appears when the answer was never a bulk response: a proxy or captive portal replying 200 with an HTML page, or a port that belongs to another service. Confirm that endpoint is the search REST root. No data is lost, but nothing gets through either. The batch is retried indefinitely, because the per-item rejections that would have capped it at four deliveries are never read, so treat this one as urgent.

"failed to parse JSON message"

[Error] [director] [target-<target id>] [elastic_output] Sender worker 2 execute() failed for elastic_output: target broken: failed to send log record: failed to parse JSON message: ...

Cause: a record is parsed as a JSON document when it is ECS-normalized, or when its text contains @timestamp anywhere at all. A plain line that merely mentions @timestamp, a truncated JSON object, or a JSON array takes the same path and fails to parse. Records that do not contain that text are wrapped into a JSON document automatically, so they never reach this error.

Fix: make the pipeline emit a JSON object for those records, or rewrite the text so it no longer contains @timestamp. No data is lost and nothing is dropped, but the record is never accepted either. It is retried every few seconds and holds up everything queued behind it, so treat it as urgent.

Configuration errors that stop the target from starting

These reach you as ValidateConfig failed for target "elastic_output": ..., or as Failed to reinitialize target "elastic_output" (attempt N). Reason: ..., and they repeat until the configuration changes. Nothing is sent while any of them lasts, and incoming data waits in the queue.

Reason textFix
no valid Elasticsearch endpoints configuredGive at least one entry under endpoints an endpoint URL
batch_size must be greater than 0 or max_payload_size_kb must be greater than 0Remove the setting to use its default, 10000 events and 4096 KB, or set a positive value
region is required when use_iam is enabled for endpoint:On amazonopensearch, set region on that endpoint, or set use_iam: false to use a user and password
failed to resolve password: or failed to resolve access key:The ${VAR} or $secret{...} reference could not be resolved. Export the variable for the Director service itself, or correct the store name and the reference
failed to build TLS config:The rest of the line names the file or the setting. Custom TLS material has to be inline PEM, or a path under the service root, and cert_name and key_name are only accepted together

The target is connected but nothing arrives in the index

Nothing fails here, so there is no error to search for. Check the following in order.

  1. debug.dont_send_logs is enabled. Records are processed by the pipeline and then discarded before anything is buffered. No counter moves, and the target reports healthy. The only trace is one line at startup, and only when debug.status is enabled as well.

    Log sending is disabled for this target (elastic_output). Logs will be processed by the pipeline but will not be sent to the target.
  2. Only one of username and password is set. The batch then goes out with no authentication header. Against a cluster that allows anonymous access it is indexed under the anonymous role, wherever that role writes, with no warning at all.

  3. On amazonopensearch, only one of key and secret is set. The pair is used only when both hold a value. Otherwise both are ignored and the default AWS credential chain is used instead, so the data may be written under the identity of the host rather than the one you configured.

  4. The records went to another index. An index field set by a pipeline overrides the target's own index for that record. Look for the documents under the name the pipeline produced before assuming they were never sent.

  5. A nested tls block sits next to the flat TLS settings. The flat ca_name, cert_name, key_name and server_name are then ignored entirely, so keep every TLS option in one shape. An unrecognized min_tls_version or max_tls_version is ignored the same way: anything other than tls1.0 through tls1.3 falls back to the defaults without an error.

  6. A custom filter_path drops items.*._index. Per-item errors then arrive with an empty index name, which makes them much harder to read. Keep the default, or include items.*._index in your own value.

  7. Documents are indexed more than once. Any retry of a partly accepted chunk sends the whole chunk again. With write_action: create and no document id the cluster generates a new id each time, so the duplicates are not detected and the delivered counter runs ahead of what the index holds.