crowdsecurity/crowdsec · error

error truncating content for %s: %w

Error message

error truncating content for %s: %w

What it means

TruncateContextMap converts evaluated context values to strings and enforces the configured maximum length per key via TruncateContext, so alerts fit console/DB limits. If TruncateContext itself errors (it JSON-marshals the values), the failure is collected per key as 'error truncating content for %s: %w' and that key is skipped rather than aborting the whole map.

Source

Thrown at pkg/alertcontext/alertcontext.go:113

	}

	return &Context{}
}

// Truncate the context map to fit in the context value length
func TruncateContextMap(contextMap map[string][]string, contextValueLen int) ([]*models.MetaItems0, []error) {
	metas := make([]*models.MetaItems0, 0)
	errors := make([]error, 0)
	ac := getAlertContext()

	for key, values := range contextMap {
		if len(values) == 0 {
			continue
		}

		valueStr, err := TruncateContext(values, ac.ContextValueLen)
		if err != nil {
			errors = append(errors, fmt.Errorf("error truncating content for %s: %w", key, err))
			continue
		}

		meta := models.MetaItems0{
			Key:   key,
			Value: valueStr,
		}
		metas = append(metas, &meta)
	}

	return metas, errors
}

// Truncate an individual []string to fit in the context value length
func TruncateContext(values []string, contextValueLen int) (string, error) {
	valueByte, err := json.Marshal(values)
	if err != nil {
		return "", fmt.Errorf("unable to dump metas: %w", err)

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped %w error to identify why json.Marshal failed for that key's values
  2. Sanitize the context values before truncation (ensure they are plain strings)
  3. Log/report the issue upstream if it reproduces — with []string input this indicates an internal invariant violation
  4. Continue is intentional: other keys are still truncated and sent, so check the resulting alert for missing metadata for this key
Defensive patterns

Strategy: try-catch

Validate before calling

for k, vals := range contextMap {
    for _, v := range vals {
        if _, err := json.Marshal(v); err != nil {
            log.Warnf("non-serializable context value for %s", k)
        }
    }
}

Type guard

func stringSliceOK(v []string) bool { return v != nil && len(v) > 0 }

Try / catch

ctxMap, errs := ac.TruncateContextMap(values)
if len(errs) > 0 {
    for _, e := range errs { log.Warnf("context key skipped: %v", e) }
    // ctxMap is still valid for remaining keys; proceed
}

Prevention

When it happens

Trigger: AppsecEventToContext or EventToContext calls TruncateContextMap; for a given key the []string values fail json.Marshal inside TruncateContext. In practice this is nearly impossible with plain strings, so it surfaces only if values contain data that breaks marshaling (unsupported channel types would be required — practically a defensive path) or contextValueLen handling leads to repeated marshal failures.

Common situations: Rare defensive branch: with []string input, json.Marshal cannot fail, so hitting this usually indicates an internal bug or a modified TruncateContext usage with non-marshallable content; errors are accumulated and reported together after the loop.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/cdf6ae11539e0d80. Report an issue: GitHub.