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

  1. Change the third tuple element to a plain dict of string->string headers, e.g. ('body', 200, {'Content-Type': 'text/html'})
  2. Return only 2 elements (body, status) if you have no extra headers
  3. 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

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


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)