{"record":{"id":"370b7095e8b4942e","repo":"influxdata/influxdb","slug":"custom-partition-template-must-have-at-least-one-part","errorCode":null,"errorMessage":"Custom partition template must have at least one part","messagePattern":"Custom partition template must have at least one part","errorType":"validation","errorClass":"ValidationError","httpStatus":null,"severity":"error","filePath":"core/data_types/src/partition_template.rs","lineNumber":203,"sourceCode":"};\n\nuse chrono::{\n    DateTime, Days, Months, Utc,\n    format::{self, Numeric, StrftimeItems},\n};\nuse generated_types::influxdata::iox::partition_template::v1 as proto;\nuse murmur3::murmur3_32;\nuse percent_encoding::{AsciiSet, CONTROLS, percent_decode_str};\nuse schema::TIME_COLUMN_NAME;\nuse thiserror::Error;\n\nuse crate::{MismatchedNumPartsError, PartitionKey, PartitionKeyBuilder};\n\n/// Reasons a user-specified partition template isn't valid.\n#[derive(Debug, Error)]\npub enum ValidationError {\n    /// The partition template didn't define any parts.\n    #[error(\"Custom partition template must have at least one part\")]\n    NoParts,\n\n    /// The partition template exceeded the maximum allowed number of parts.\n    #[error(\n        \"Custom partition template specified {specified} parts. \\\n        Partition templates may have a maximum of {MAXIMUM_NUMBER_OF_TEMPLATE_PARTS} parts.\"\n    )]\n    TooManyParts {\n        /// The number of template parts that were present in the user-provided custom partition\n        /// template.\n        specified: usize,\n    },\n\n    /// The partition template defines a [`TimeFormat`] part, but the\n    /// provided strftime formatter is invalid.\n    ///\n    /// [`TimeFormat`]: [`proto::template_part::Part::TimeFormat`]\n    #[error(\"invalid strftime format in partition template: {0}\")]","sourceCodeStart":185,"sourceCodeEnd":221,"githubUrl":"https://github.com/influxdata/influxdb/blob/06200ef96ba82c5f6727e5038a83af8e722c6875/core/data_types/src/partition_template.rs#L185-L221","documentation":"This error indicates a user-provided custom partition template contains zero parts. A partition template must define at least one part (e.g., a time format, tag value, or bucket) because an empty template cannot partition data. The library validates this in `PartitionTemplateBuilder`/validation code and rejects the template up front.","triggerScenarios":"Building a `PartitionTemplateBuilder` and calling `build()` (or validating a proto `PartitionTemplate`) without pushing any template parts, e.g. no `add_time_part`/`add_tag_part`/`add_bucket_part` calls, or building from an empty parts list.","commonSituations":"Constructing a template programmatically from dynamic config where all parts were filtered out (e.g., unset columns); parsing a user-supplied template string that yielded no parts; API/DDL requests with an empty parts array.","solutions":["Add at least one part to the template before calling `build()` (e.g., `builder.add_tag_part(\"region\")` or a time-format part)","Check upstream config/inputs: if parts are built from a list, reject empty lists earlier with a clear user-facing message","If the intent is no partitioning, omit the custom partition template entirely rather than passing an empty one"],"exampleFix":"// before\nlet template = PartitionTemplateBuilder::new().build()?; // NoParts\n// after\nlet template = PartitionTemplateBuilder::new()\n    .add_strftime_format(\"%Y-%m-%d\")\n    .build()?;","handlingStrategy":"validation","validationCode":"fn validate_template_parts(parts: &[TemplatePart]) -> Result<(), String> {\n    if parts.is_empty() {\n        return Err(\"partition template requires at least one part\".into());\n    }\n    Ok(())\n}","typeGuard":"fn has_parts(t: &PartitionTemplateBuilder) -> bool {\n    t.num_parts() > 0 // or inspect the parts collection\n}","tryCatchPattern":"let template = builder.build().map_err(|e| match e {\n    ValidationError::NoParts => anyhow!(\"configure at least one partition part (tag/time/bucket) before building\"),\n    other => anyhow!(other),\n})?;","preventionTips":["After building a template from dynamic config, assert the parts list is non-empty before persisting it","Treat an 'empty template' DDL request as a user input error at the API boundary","When defaulting is desired, add a sane default part (e.g., daily strftime) instead of leaving the template empty"],"tags":["rust","partition-template","validation","config"],"backgroundTag":"empty-required-field","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"}