{"record":{"id":"9d64de571baa199e","repo":"redis/node-redis","slug":"tls-certificates-not-available-after-maxwaitms-m","errorCode":null,"errorMessage":"TLS certificates not available after ${maxWaitMs}ms","messagePattern":"TLS certificates not available after (.+?)ms","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/test-utils/lib/dockers.ts","lineNumber":321,"sourceCode":"    `${DEFAULT_TLS_PATH}/${certName}.key`,\n  ];\n\n  while (Date.now() - startTime < maxWaitMs) {\n    try {\n      await Promise.all(\n        certFiles.map(file =>\n          execAsync(\"docker\", [\"exec\", dockerId, \"test\", \"-f\", file]),\n        ),\n      );\n      // All files exist\n      return;\n    } catch {\n      // Not all files exist yet, wait and retry\n      await setTimeout(100);\n    }\n  }\n\n  throw new Error(`TLS certificates not available after ${maxWaitMs}ms`);\n}\n\n/**\n * Spawns a TLS-enabled Redis server Docker container with both TLS and non-TLS ports\n */\nexport async function spawnTlsRedisServerDocker(\n  options: RedisServerDockerOptions,\n  serverArguments: Array<string> = [],\n  tlsConfig?: TlsConfig,\n): Promise<TlsRedisServerDocker> {\n  const port = (await portIterator.next()).value;\n  const tlsPort = (await portIterator.next()).value;\n  const clientCertCN = tlsConfig?.clientCertCN;\n\n  // Use provided CN for cert name, otherwise use default 'client' cert\n  const certName = clientCertCN ?? DEFAULT_CLIENT_CERT_NAME;\n\n  const dockerArgs = [","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/redis/node-redis/blob/90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58/packages/test-utils/lib/dockers.ts#L303-L339","documentation":"waitForTlsCertificates polls `docker exec <id> test -f <file>` for ca.crt, <cert>.crt, and <cert>.key every 100ms, retrying until all exist or maxWaitMs (default 30000ms) elapses. On timeout it throws. It gates loadTlsCertificates so that reads only happen once the container's cert generation completes.","triggerScenarios":"The Redis image failed to generate TLS certificates within 30s (cert-gen script errored or is absent); the container crashed mid-startup; the certName (clientCertCN) does not match the files the image produces.","commonSituations":"Slow CI disk making cert generation lag; image variant without the TLS bootstrap script; custom clientCertCN that the image does not materialize; clock/resource contention on a loaded runner.","solutions":["Inspect the container logs for the cert-generation step: docker logs <id>","Pass a larger maxWaitMs if the environment is slow","Verify the certName/clientCertCN matches a cert the image actually produces (default is 'client')"],"exampleFix":"// before — default 30s budget exceeded\nawait waitForTlsCertificates(dockerId, certName);\n\n// after — allow more time on slow CI\nawait waitForTlsCertificates(dockerId, certName, 60_000);","handlingStrategy":"retry","validationCode":"async function safeWaitForTls(dockerId: string, certName: string, maxWaitMs = 60_000): Promise<void> {\n  try {\n    await waitForTlsCertificates(dockerId, certName, maxWaitMs);\n  } catch (e) {\n    const logs = await execAsync('docker', ['logs', dockerId]).then(r => r.stderr, () => '');\n    throw new Error(`${(e as Error).message}\\nContainer logs:\\n${logs}`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await waitForTlsCertificates(dockerId, certName, 60_000);\n} catch (e) {\n  if (e instanceof Error && /TLS certificates not available/.test(e.message)) {\n  }\n  throw e;\n}","preventionTips":["Pass a larger maxWaitMs on slow CI runners","Verify the image's TLS bootstrap script runs (docker logs) before relying on cert generation","Ensure certName/clientCertCN matches a cert the image actually produces"],"tags":["docker","tls","certificates","timeout","test-utils","polling"],"backgroundTag":null,"analyzedSha":"90fd0652bc3f2a0a1b2f79fa9096b02a86b0ac58","analyzedAt":"2026-08-11T15:37:21.243Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}