neondatabase/neon · warning · ApiError

Failed to configure failpoints: {err_msg}

Error message

Failed to configure failpoints: {err_msg}

What it means

Returned as HTTP 400 BadRequest by failpoints_handler in neon's http-utils when apply_failpoint(name, actions) — which wraps fail::cfg plus the extra 'exit' action — returns an Err. The actions string must follow the failpoints-crate format (e.g. 'off', 'return', 'return(42)', 'pause', '10%return', 'exit'); an unparseable action or an unknown directive produces an error message that is embedded into this response.

Source

Thrown at libs/http-utils/src/failpoints.rs:42

    mut request: Request<Body>,
    _cancel: CancellationToken,
) -> Result<Response<Body>, ApiError> {
    if !fail::has_failpoints() {
        return Err(ApiError::BadRequest(anyhow::anyhow!(
            "Cannot manage failpoints because neon was compiled without failpoints support"
        )));
    }

    let failpoints: ConfigureFailpointsRequest = json_request(&mut request).await?;
    for fp in failpoints {
        tracing::info!("cfg failpoint: {} {}", fp.name, fp.actions);

        // We recognize one extra "action" that's not natively recognized
        // by the failpoints crate: exit, to immediately kill the process
        let cfg_result = apply_failpoint(&fp.name, &fp.actions);

        if let Err(err_msg) = cfg_result {
            return Err(ApiError::BadRequest(anyhow::anyhow!(
                "Failed to configure failpoints: {err_msg}"
            )));
        }
    }

    json_response(StatusCode::OK, ())
}

View on GitHub (pinned to 8f60b04da4)

Solutions

  1. Check the err_msg in the response — it names the exact action string that failed to parse
  2. Use valid actions: off, return, return(value), pause, delay, probability-prefixed forms like '10%return', or the neon extension 'exit'
  3. Validate the actions string against the failpoints crate cfg syntax before sending the batch
  4. Fix only the failing entry; entries before it were already applied, so re-send the corrected one

Example fix

# before
curl -X POST localhost:9898/failpoints -d '[{"name":"fp1","actions":"sleep(1000)"}]'
# 400 Failed to configure failpoints

# after
curl -X POST localhost:9898/failpoints -d '[{"name":"fp1","actions":"pause"}]'
Defensive patterns

Strategy: validation

Validate before calling

# Validate actions against the accepted grammar before sending:
ACTION_RE='^(off|return(\([^)]*\))?|pause|delay|exit|[0-9]+%(return(\([^)]*\))?|pause|delay|exit))$'
for fp in "${FAILPOINTS[@]}"; do
  name="${fp%%=*}"; actions="${fp#*=}"
  [[ "$actions" =~ $ACTION_RE ]] || { echo "bad actions: $actions"; exit 1; }
done

Type guard

function isValidFailpointAction(a) {
  return /^(off|return(\([^)]*\))?|pause|delay|exit|\d+%(&?.*)?)$/.test(a);
}

Try / catch

# Report the offending entry and continue rather than aborting the scenario:
if ! curl -sf -X POST localhost:9898/failpoints -d @fp.json; then
  echo "failpoint config rejected; check actions syntax per the failpoints crate cfg format"
  exit 1
fi

Prevention

When it happens

Trigger: POST /failpoints with body [{"name":"...","actions":"sleep(100)"}] where 'sleep(100)' is not valid syntax (the crate uses 'delay'/'pause' style actions); also malformed probability like 'return(abc)' or an actions string the failpoints cfg parser rejects. The first failing entry aborts the whole request with 400.

Common situations: Test scripts assuming fail crate action names that differ from the failpoints crate ('sleep' vs 'delay'); copy-pasted actions from docs of a different failpoint library; typos like 'retrn' or 'pause 100' instead of 'pause(100)'.

Related errors


AI-assisted analysis of neondatabase/neon@8f60b04da4 (2026-08-16). Data as JSON: /api/errors/001ff75e4791bcf8. Report an issue: GitHub.