{"record":{"id":"bbd81f8811f0db19","repo":"influxdata/influxdb","slug":"expected-expected-parts-in-key-due-to-template-passed-in","errorCode":null,"errorMessage":"Expected {expected} parts in key due to template passed in, found {found}. (Note: this may be due to a provided `part` containing the delimiter, `|`, resulting in the key containing more parts than necessary)","messagePattern":"Expected (.+?) parts in key due to template passed in, found (.+?)\\. \\(Note: this may be due to a provided `part` containing the delimiter, `\\|`, resulting in the key containing more parts than necessary\\)","errorType":"validation","errorClass":"MismatchedNumPartsError","httpStatus":null,"severity":"error","filePath":"core/data_types/src/partition.rs","lineNumber":243,"sourceCode":"        <String as sqlx::Encode<sqlx::Sqlite>>::encode(self.0.to_string(), buf)\n    }\n}\n\nimpl sqlx::Decode<'_, sqlx::Sqlite> for PartitionKey {\n    fn decode(\n        value: <sqlx::Sqlite as sqlx::database::Database>::ValueRef<'_>,\n    ) -> Result<Self, Box<dyn std::error::Error + 'static + Send + Sync>> {\n        Ok(Self(\n            <String as sqlx::Decode<sqlx::Sqlite>>::decode(value)?.into(),\n        ))\n    }\n}\n\n/// An error struct that could be returned from [`NamespacePartitionTemplateOverride::part_key()`]\n/// if validation fails. [`Self::expected`] will be equal to the number of parts which the template had,\n/// and [`Self::found`] will be equal to the number of fields passed in as the argument `parts`\n#[derive(Debug, Copy, Clone, Error)]\n#[error(\n    \"Expected {expected} parts in key due to template passed in, found {found}. (Note: this may be due to a provided `part` containing the delimiter, `|`, resulting in the key containing more parts than necessary)\"\n)]\npub struct MismatchedNumPartsError {\n    /// The number of parts that the tmpl passed into [`NamespacePartitionTemplateOverride::part_key()`] had\n    pub expected: usize,\n    /// The number of parts that were passed into [`NamespacePartitionTemplateOverride::part_key()`]\n    pub found: usize,\n}\n\n/// A utility struct to create a [`PartitionKey`] for a specific\n/// [`NamespacePartitionTemplateOverride`] and verify that this key has the correct amount of\n/// `parts` in it to be used with the provided template.\n#[derive(Debug)]\npub struct PartitionKeyBuilder {\n    /// The incremental string that is built as [`Self::push()`] is called multiple times, and what\n    /// will be turned into the [`PartitionKey`] if validation succeeds.\n    key: String,\n    /// The number of expected `parts` that this key should have, based on the template provided in","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/core/data_types/src/partition.rs#L225-L261","documentation":"MismatchedNumPartsError is returned from NamespacePartitionTemplateOverride::part_key() when the number of part values supplied does not match the number of parts declared by the template. expected is the template's part count and found is the number of values passed in. The library throws it because the key can only be built when every templated part receives exactly one value.","triggerScenarios":"Calling part_key() with fewer or more values than the partition template declares, e.g. a template with 2 parts but only 1 value passed, or a single part value that itself contains the '|' delimiter causing extra parts to appear.","commonSituations":"Changing a table's partition template (adding a tag/part column) while writers still send the old number of values; tag values that literally contain '|' producing more split parts than expected; schema drift between producer and template configuration.","solutions":["Compare the expected/found numbers in the message with your partition template definition and pass exactly that many values.","Check each part value for the '|' delimiter and escape, reject, or re-map values containing it.","Re-read the table's current partition template after any ALTER TABLE change and update your writer accordingly.","Compute the part count from the template at runtime instead of hardcoding it."],"exampleFix":"// before\nlet key = tmpl.part_key(&[region])?; // template has 2 parts\n// after\nlet key = tmpl.part_key(&[region, day])?; // one value per template part","handlingStrategy":"validation","validationCode":"let expected = tmpl.num_parts(); // part count from the template\nlet found = parts.len();\nif found != expected || parts.iter().any(|p| p.contains('|')) {\n    return Err(\"part values must match template count and contain no '|'\".into());\n}","typeGuard":null,"tryCatchPattern":"match tmpl.part_key(&parts) {\n    Ok(key) => use(key),\n    Err(MismatchedNumPartsError { expected, found }) => {\n        log::error!(\"template needs {expected} parts, got {found}; refresh template definition\");\n        reload_template_and_retry()\n    }\n}","preventionTips":["Derive the number of part values from the live template, never hardcode it.","After ALTER TABLE partition template changes, redeploy or refresh writers.","Reject or escape tag values containing the '|' delimiter.","Add a unit test asserting part_key() arity for each template in use."],"tags":["rust","partitioning","argument-count","influxdb"],"backgroundTag":"argument-count-mismatch","analyzedSha":"06200ef96ba82c5f6727e5038a83af8e722c6875","analyzedAt":"2026-09-19T12:55:30.003Z","contentChangedAt":"2026-09-19T12:55:30.003Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}