{"record":{"id":"c87d02d8d956efc4","repo":"langgenius/dify","slug":"knowledge-fs-base-url-and-knowledge-fs-jwt-secret","errorCode":null,"errorMessage":"KNOWLEDGE_FS_BASE_URL and KNOWLEDGE_FS_JWT_SECRET must be configured together","messagePattern":"KNOWLEDGE_FS_BASE_URL and KNOWLEDGE_FS_JWT_SECRET must be configured together","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"api/configs/extra/knowledge_fs_config.py","lineNumber":61,"sourceCode":"        if value is None:\n            return None\n        parsed = urlsplit(value)\n        if parsed.scheme not in {\"http\", \"https\"} or not parsed.netloc:\n            raise ValueError(\"KNOWLEDGE_FS_BASE_URL must be an absolute HTTP(S) URL\")\n        try:\n            _ = parsed.port\n        except ValueError as exc:\n            raise ValueError(\"KNOWLEDGE_FS_BASE_URL must include a valid port\") from exc\n        if parsed.username or parsed.password or parsed.query or parsed.fragment:\n            raise ValueError(\"KNOWLEDGE_FS_BASE_URL must not include credentials, query, or fragment\")\n        return value.rstrip(\"/\")\n\n    @model_validator(mode=\"after\")\n    def validate_enabled_connection(self) -> \"KnowledgeFSConfig\":\n        if not self.KNOWLEDGE_FS_ENABLED:\n            return self\n        if bool(self.KNOWLEDGE_FS_BASE_URL) != bool(self.KNOWLEDGE_FS_JWT_SECRET):\n            raise ValueError(\"KNOWLEDGE_FS_BASE_URL and KNOWLEDGE_FS_JWT_SECRET must be configured together\")\n        if not self.KNOWLEDGE_FS_BASE_URL:\n            raise ValueError(\"KnowledgeFS connection settings are required when the integration is enabled\")\n        return self\n","sourceCodeStart":43,"sourceCodeEnd":65,"githubUrl":"https://github.com/langgenius/dify/blob/ef8544b173fd6cd7a8e71df2cab576e52bebbfbc/api/configs/extra/knowledge_fs_config.py#L43-L65","documentation":"Raised by the after-model validator validate_enabled_connection when exactly one of KNOWLEDGE_FS_BASE_URL / KNOWLEDGE_FS_JWT_SECRET is set (XOR). The integration requires both because the URL identifies the gateway and the JWT secret signs service tokens; a half-configured state would either fail to connect or send unsigned requests.","triggerScenarios":"Enabling KNOWLEDGE_FS_ENABLED=true with KNOWLEDGE_FS_BASE_URL set but KNOWLEDGE_FS_JWT_SECRET unset (or under 32 chars, which normalizes to None), or vice versa.","commonSituations":"Operator configures the URL in one env file and the secret in another but forgets one; or the JWT secret is blanked/short so the before-validator converts it to None.","solutions":["Set BOTH KNOWLEDGE_FS_BASE_URL and KNOWLEDGE_FS_JWT_SECRET (>=32 chars) in the same environment.","If disabling the integration, set KNOWLEDGE_FS_ENABLED=false and unset both.","Verify the JWT secret was not truncated by shell quoting and meets min_length=32."],"exampleFix":"// before\nKNOWLEDGE_FS_ENABLED=true\nKNOWLEDGE_FS_BASE_URL=https://kfs.example:8443\n// (KNOWLEDGE_FS_JWT_SECRET missing)\n// after\nKNOWLEDGE_FS_ENABLED=true\nKNOWLEDGE_FS_BASE_URL=https://kfs.example:8443\nKNOWLEDGE_FS_JWT_SECRET=<32+ char shared secret>","handlingStrategy":"validation","validationCode":"def kfs_pair_ok(url: str | None, secret: str | None) -> bool:\n    return bool(url) == bool(secret) and (not secret or len(secret) >= 32)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Configure KNOWLEDGE_FS_BASE_URL and KNOWLEDGE_FS_JWT_SECRET together in the same env file.","Ensure the JWT secret is at least 32 characters.","Leave both unset when KNOWLEDGE_FS_ENABLED=false."],"tags":["config","pydantic","knowledge-fs","required-field"],"backgroundTag":null,"analyzedSha":"ef8544b173fd6cd7a8e71df2cab576e52bebbfbc","analyzedAt":"2026-08-12T05:15:17.394Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}