{"record":{"id":"c9872b60e69a6282","repo":"quickwit-oss/quickwit","slug":"source-type-cannot-be-changed-current-type","errorCode":null,"errorMessage":"source type cannot be changed, current type {}","messagePattern":"source type cannot be changed, current type (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"quickwit/quickwit-config/src/source_config/mod.rs","lineNumber":290,"sourceCode":"    fn validate_update(&self, new_source_params: &SourceParams) -> anyhow::Result<()> {\n        match (self, new_source_params) {\n            (\n                SourceParams::File(FileSourceParams::Notifications(current)),\n                SourceParams::File(FileSourceParams::Notifications(new)),\n            ) => current.validate_update(new),\n            (SourceParams::Kafka(current), SourceParams::Kafka(new)) => {\n                current.validate_update(new)\n            }\n            (SourceParams::Kinesis(current), SourceParams::Kinesis(new)) => {\n                current.validate_update(new)\n            }\n            (SourceParams::PubSub(current), SourceParams::PubSub(new)) => {\n                current.validate_update(new)\n            }\n            (SourceParams::Pulsar(current), SourceParams::Pulsar(new)) => {\n                current.validate_update(new)\n            }\n            (current, new) if current.source_type() != new.source_type() => Err(anyhow::anyhow!(\n                \"source type cannot be changed, current type {}\",\n                current.source_type(),\n            )),\n            _ => Err(anyhow::anyhow!(\n                \"source type {} cannot be updated\",\n                self.source_type(),\n            )),\n        }\n    }\n}\n\n#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, utoipa::ToSchema)]\n#[serde(rename_all = \"snake_case\")]\npub enum FileSourceMessageType {\n    /// See <https://docs.aws.amazon.com/AmazonS3/latest/userguide/notification-content-structure.html>\n    S3Notification,\n    /// A string with the URI of the file (e.g `s3://bucket/key`)\n    RawUri,","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/quickwit-oss/quickwit/blob/a39730c5cdcd1a4fe798403737ae293999ea21f8/quickwit/quickwit-config/src/source_config/mod.rs#L272-L308","documentation":"SourceConfig::validate_update checks that a source update does not change the source's type. Sources (kafka, kinesis, pulsar, pubsub, file, ingest...) have type-specific params; switching types via update is unsupported — delete and recreate the source instead.","triggerScenarios":"Calling the source update API/CLI (e.g. `quickwit source update` or PUT /indexes/{index}/sources/{source}) with a new source config whose `source_type()` differs from the existing source's type, e.g. updating a kafka source with a pulsar config.","commonSituations":"Reusing a source config YAML template for a different source technology while keeping the same source ID; swapping a deprecated source type for a new one in place; automation that overwrites source definitions wholesale.","solutions":["Delete the existing source (`quickwit source delete`) and create a new source with the desired type via `quickwit source create`.","Keep the `source.type` field identical when editing params (e.g. only change kafka topic/broker settings).","Use a different source ID if both source types must coexist on the same index."],"exampleFix":"# before: updating source 'my-source' of type kafka with\ntype: pulsar\n# after: delete then create\nquickwit source delete --index my-index --source my-source\nquickwit source create --index my-index --source-config new-pulsar-source.yaml","handlingStrategy":"validation","validationCode":"async function safeUpdateSource(indexId, sourceId, newCfg) {\n  const current = await getSource(indexId, sourceId);\n  if (current.source_type !== newCfg.type) {\n    throw new Error(`source type cannot change: delete and recreate ${sourceId}`);\n  }\n  return updateSource(indexId, sourceId, newCfg);\n}","typeGuard":"const typesMatch = (current, next) => current.type === next.type;","tryCatchPattern":"try {\n  await updateSource(indexId, sourceId, cfg);\n} catch (e) {\n  if (String(e).includes('source type cannot be changed')) {\n    await deleteSource(indexId, sourceId);\n    await createSource(indexId, sourceId, cfg);\n  } else throw e;\n}","preventionTips":["Treat source `type` as immutable; only edit params within the same type.","When migrating between source technologies, always delete + create under a new config.","Avoid bulk automation that overwrites source definitions wholesale without diffing types first.","Use distinct source IDs for different technologies instead of reusing one."],"tags":["config","sources","validation","immutable-field"],"backgroundTag":"incompatible-source-type","analyzedSha":"a39730c5cdcd1a4fe798403737ae293999ea21f8","analyzedAt":"2026-09-08T13:19:37.784Z","contentChangedAt":"2026-09-08T13:19:37.784Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}