{"record":{"id":"5ba02b95bd325efe","repo":"AlistGo/alist","slug":"private-key-or-certificate-is-not-provided","errorCode":null,"errorMessage":"private key or certificate is not provided","messagePattern":"private key or certificate is not provided","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/ftp.go","lineNumber":275,"sourceCode":"\t\t}\n\t}\n\treturn func() (int, int, bool) {\n\t\tidxPort := rand.Intn(totalLength)\n\t\tfor _, g := range groups {\n\t\t\tif idxPort >= g.Length {\n\t\t\t\tidxPort -= g.Length\n\t\t\t} else {\n\t\t\t\treturn g.ExposedStart + idxPort, g.ListenedStart + idxPort, true\n\t\t\t}\n\t\t}\n\t\t// unreachable\n\t\treturn 0, 0, false\n\t}\n}\n\nfunc getTlsConf(keyPath, certPath string) (*tls.Config, error) {\n\tif keyPath == \"\" || certPath == \"\" {\n\t\treturn nil, errors.New(\"private key or certificate is not provided\")\n\t}\n\tcert, err := os.ReadFile(certPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tkey, err := os.ReadFile(keyPath)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\ttlsCert, err := tls.X509KeyPair(cert, key)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn &tls.Config{Certificates: []tls.Certificate{tlsCert}}, nil\n}\n","sourceCodeStart":257,"sourceCodeEnd":291,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/server/ftp.go#L257-L291","documentation":"Returned by getTlsConf before any file I/O when either the private key path or the certificate path is empty. The two TLS settings are only meaningful together; leaving one blank aborts TLS setup, which in turn leaves the FTP driver with a nil tls.Config (surfacing later as 'TLS config not provided' on AUTH TLS).","triggerScenarios":"Server start with only one of ftp.tls_cert_file / ftp.tls_key_file configured; setting a cert path but leaving the key path at its empty default (or vice versa).","commonSituations":"Filling in the certificate but not the key when configuring FTPS; wiping one field during settings import/restore; using a combined PEM for both and only entering it in one field (the code requires both paths explicitly).","solutions":["Set both the private key and certificate paths in the FTP settings","Double-check neither field was cleared after a settings migration or backup restore","Verify the referenced files exist and the pair matches before restarting"],"exampleFix":"// before\nftp:\n  tls_cert_file: \"/etc/alist/cert.pem\"\n  tls_key_file: \"\"\n// after\nftp:\n  tls_cert_file: \"/etc/alist/cert.pem\"\n  tls_key_file: \"/etc/alist/key.pem\"","handlingStrategy":"validation","validationCode":"func tlsPathsComplete(keyPath, certPath string) bool {\n    return keyPath != \"\" && certPath != \"\"\n}","typeGuard":null,"tryCatchPattern":"conf, err := getTlsConf(keyPath, certPath)\nif err != nil && strings.Contains(err.Error(), \"private key or certificate is not provided\") {\n    // config bug: exactly one of the two paths is empty — fix settings before retry\n    return nil\n}","preventionTips":["Treat ftp tls cert and key settings as one unit in config templates","Add a startup health check that fails fast when FTPS is expected but material is missing","Keep certificates under a stable path owned by the service user"],"tags":["ftp","ftp-tls","certificates","config"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}