temporalio/temporal · error
duplicate connection attr: %v:%v, %v:%v
Error message
duplicate connection attr: %v:%v, %v:%v
What it means
Returned by buildDSNAttr when a user-supplied ConnectAttributes key duplicates a parameter that is already present in the DSN built from the sqlite config (or another conflicting source). Allowing duplicates would create ambiguous URI query parameters, so the builder rejects it explicitly, listing both conflicting values.
Source
Thrown at common/persistence/sql/sqlplugin/sqlite/plugin.go:192
"file:%s?%v",
cfg.DatabaseName,
vals.Encode(),
)
return dsn, nil
}
func buildDSNAttr(cfg *config.SQL) (url.Values, error) {
parameters := url.Values{}
// sort ConnectAttributes to get a deterministic order
keys := expmaps.Keys(cfg.ConnectAttributes)
sort.Strings(keys)
for _, k := range keys {
key := strings.TrimSpace(k)
value := strings.TrimSpace(cfg.ConnectAttributes[k])
if parameters.Get(key) != "" {
return nil, fmt.Errorf("duplicate connection attr: %v:%v, %v:%v",
key,
parameters.Get(key),
key, value,
)
}
if _, isValidQueryParameter := queryParameters[key]; isValidQueryParameter {
parameters.Set(key, value)
continue
}
// assume pragma
parameters.Add("_pragma", fmt.Sprintf("%s=%s", key, value))
}
// set time format
parameters.Add("_time_format", "sqlite")
return parameters, nil
}View on GitHub (pinned to bde624efd1)
Solutions
- Remove the duplicate key from cfg.ConnectAttributes — keep only the plugin-provided value.
- If you must override, check buildDSN to see which parameters are pre-populated and choose non-conflicting ones.
- Deduplicate keys in your config template/pipeline before it reaches the plugin.
- Review the error message: it shows both the existing value and your conflicting value.
Example fix
// before
connectAttributes: {"_txlock": "immediate", "cache": "shared", "_txlock": "exclusive"}
// after
connectAttributes: {"cache": "shared"} Defensive patterns
Strategy: validation
Validate before calling
// Go: dedupe and check against plugin-provided params
reserved := map[string]bool{"mode": true, "cache": true, "_txlock": true}
for k := range cfg.ConnectAttributes {
if reserved[strings.TrimSpace(k)] {
return fmt.Errorf("connect attribute %q conflicts with DSN defaults", k)
}
} Try / catch
// Go
if err != nil && strings.Contains(err.Error(), "duplicate connection attr") {
return fmt.Errorf("remove conflicting sqlite ConnectAttributes: %w", err)
} Prevention
- Don't set mode/cache/_txlock in ConnectAttributes (plugin provides them)
- Deduplicate keys in config templating pipelines
- Read buildDSN to learn which parameters are pre-populated
- Validate config at startup with a fail-fast check
When it happens
Trigger: Passing a ConnectAttributes entry whose key collides with parameters already added to the sqlite DSN (e.g. specifying 'mode' or 'cache' in ConnectAttributes when the DSN path/query already encodes it), when calling the sqlite plugin's connection creation path.
Common situations: Copy-pasting MySQL/Postgres connect attributes into a sqlite config; explicitly setting _txlock, mode, or cache that the plugin already sets; config templating accidentally inserting the same key twice.
Related errors
- error building DSN: %w
- requires a StartTime or CloseTime
- only one of certData or certFile properties should be specif
- missing current cluster metadata under clusterMetadata.Clust
- hosts are missing in static hosts for service: ${service}
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/8d92f300d08806c1.
Report an issue: GitHub.