{"record":{"id":"607b75549428b099","repo":"langgenius/dify","slug":"pubsub-redis-url-must-be-set-when-default-redis-ur","errorCode":null,"errorMessage":"PUBSUB_REDIS_URL must be set when default Redis URL cannot be constructed","messagePattern":"PUBSUB_REDIS_URL must be set when default Redis URL cannot be constructed","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"api/configs/middleware/cache/redis_pubsub_config.py","lineNumber":76,"sourceCode":"            \"the risk of data loss from Redis auto-eviction under memory pressure.\\n\"\n            \"Also accepts ENV: EVENT_BUS_REDIS_CHANNEL_TYPE.\"\n        ),\n        default=\"pubsub\",\n    )\n\n    PUBSUB_STREAMS_RETENTION_SECONDS: int = Field(\n        validation_alias=AliasChoices(\"EVENT_BUS_STREAMS_RETENTION_SECONDS\", \"PUBSUB_STREAMS_RETENTION_SECONDS\"),\n        description=(\n            \"When using 'streams', expire each stream key this many seconds after the last event is published. \"\n            \"Also accepts ENV: EVENT_BUS_STREAMS_RETENTION_SECONDS.\"\n        ),\n        default=600,\n    )\n\n    def _build_default_pubsub_url(self) -> str:\n        defaults = _redis_defaults(self)\n        if not defaults.REDIS_HOST or not defaults.REDIS_PORT:\n            raise ValueError(\"PUBSUB_REDIS_URL must be set when default Redis URL cannot be constructed\")\n\n        scheme = \"rediss\" if defaults.REDIS_USE_SSL else \"redis\"\n        username = defaults.REDIS_USERNAME or None\n        password = defaults.REDIS_PASSWORD or None\n\n        userinfo = \"\"\n        if username:\n            userinfo = quote_plus(username)\n        if password:\n            password_part = quote_plus(password)\n            userinfo = f\"{userinfo}:{password_part}\" if userinfo else f\":{password_part}\"\n        if userinfo:\n            userinfo = f\"{userinfo}@\"\n\n        db = defaults.REDIS_DB\n\n        netloc = f\"{userinfo}{defaults.REDIS_HOST}:{defaults.REDIS_PORT}\"\n        return urlunparse((scheme, netloc, f\"/{db}\", \"\", \"\", \"\"))","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/configs/middleware/cache/redis_pubsub_config.py#L58-L94","documentation":"Raised by RedisPubSubConfig._build_default_pubsub_url when neither PUBSUB_REDIS_URL (alias EVENT_BUS_REDIS_URL) is set nor the base REDIS_HOST/REDIS_PORT are available to synthesize a URL. The pubsub transport needs a concrete Redis endpoint to connect.","triggerScenarios":"Accessing normalized_pubsub_redis_url while PUBSUB_REDIS_URL is unset and REDIS_HOST or REDIS_PORT is empty/falsy (e.g. partial Redis config).","commonSituations":"Running the event bus without setting REDIS_* or EVENT_BUS_REDIS_URL, or pointing at a separate Redis for pubsub but misspelling the var.","solutions":["Set PUBSUB_REDIS_URL (or EVENT_BUS_REDIS_URL) to a full redis:// URL.","Or ensure REDIS_HOST and REDIS_PORT are both set so the default URL can be built.","If using Redis Cluster/Sentinel, provide PUBSUB_REDIS_URL explicitly since host/port synthesis won't match."],"exampleFix":"// before\nREDIS_HOST=\nPUBSUB_REDIS_URL=\n// after\nPUBSUB_REDIS_URL=redis://:password@redis:6379/0\n// or\nREDIS_HOST=redis\nREDIS_PORT=6379","handlingStrategy":"validation","validationCode":"def pubsub_resolvable(pubsub_url: str | None, redis_host: str | None, redis_port: int | None) -> bool:\n    return bool(pubsub_url and pubsub_url.strip()) or bool(redis_host and redis_port)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Set PUBSUB_REDIS_URL explicitly for production event bus.","Ensure REDIS_HOST and REDIS_PORT are both populated when relying on synthesis.","For Redis Cluster, always provide the full URL."],"tags":["config","pydantic","redis","event-bus","required-field"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}