influxdata/influxdb · error · anyhow::Error
expected a dictionary in header item
Error message
expected a dictionary in header item
What it means
When processing a plugin return value under Flask conventions, a 3-element tuple is interpreted as (body, status_or_headers, headers). If the third element is not a Python dict, process_flask_response bails with 'expected a dictionary in header item'. The library requires the third tuple slot to be a dict of header name/value string pairs.
Solutions
- Change the third tuple element to a plain dict of string->string headers, e.g. ('body', 200, {'Content-Type': 'text/html'})
- Return only 2 elements (body, status) if you have no extra headers
- If headers come from Flask as a list of pairs, convert with dict(headers) before returning
Example fix
// before (plugin)
return 'ok', 200, [('Content-Type', 'text/html')]
// after (plugin)
return 'ok', 200, {'Content-Type': 'text/html'} Defensive patterns
Strategy: type-guard
Validate before calling
def _ok_headers(h):
return isinstance(h, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in h.items()) Type guard
def is_header_dict(h):
return isinstance(h, dict) and all(isinstance(k, str) and isinstance(v, str) for k, v in h.items()) Prevention
- Always return headers as a plain dict of str->str, never a list of tuples or Headers object
- Return at most a 3-element tuple: (body, [status|headers], [headers])
- Add a unit test asserting the exact return shape of your plugin
When it happens
Trigger: A request-trigger plugin returns a 3-tuple whose third element is not a dict: e.g. return 'body', 200, [('Content-Type','text/html')] (Flask-style list of tuples), a headers object, None, or a string.
Common situations: Developers copy Flask patterns where headers may be a list of (key, value) tuples; they pass a Flask Headers object or a list instead of a plain dict; they accidentally return a 3-tuple where the third element was meant to be something else.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Unsupported return type from Python function
- Python function call failed
- {0}
- At least one field is required
- CA certificate PEM should be valid
AI-assisted analysis of influxdata/influxdb@06200ef96b (2026-09-19).
Data as JSON: /api/errors/f2fa80b9faae588a.
Report an issue: GitHub.
Appendix: source
Thrown at influxdb3_py_api/src/system_py.rs:666
// Handle status and/or headers if provided
if tuple_len >= 2 {
let second = tuple.get_item(1)?;
// Check if the second item is a status code or headers
if let Ok(status_code) = second.extract::<i64>() {
status = status_code.try_into().unwrap_or(500);
} else if let Ok(header_dict) = second.cast::<PyDict>() {
// It's headers
let additional_headers: std::collections::HashMap<String, String> =
header_dict.extract()?;
headers.extend(additional_headers);
}
// If there's a third item, it must be headers
if tuple_len == 3 {
let header_item = tuple.get_item(2)?;
let Ok(header_dict) = header_item.cast::<PyDict>() else {
bail!("expected a dictionary in header item");
};
let additional_headers: std::collections::HashMap<String, String> =
header_dict.extract()?;
headers.extend(additional_headers);
}
}
return Ok((status, headers, response_body));
}
}
// Check if it's a string
if let Ok(string_val) = result.extract::<String>() {
let mut headers = default_headers.clone();
headers.insert("Content-Type".to_string(), default_mimetype.to_string());
return Ok((default_status, headers, string_val));
}
View on GitHub (pinned to 06200ef96b)