{"record":{"id":"380b2527a4c0282d","repo":"FoundationAgents/MetaGPT","slug":"rw-api-not-exists","errorCode":null,"errorMessage":"{rw_api} not exists","messagePattern":"(.+?) not exists","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"metagpt/environment/base_env.py","lineNumber":63,"sourceCode":"\n\ndef mark_as_writeable(func):\n    \"\"\"mark functionn as a writeable one in ExtEnv, it does something to ExtEnv\"\"\"\n    env_write_api_registry[func.__name__] = get_function_schema(func)\n    return func\n\n\nclass ExtEnv(BaseEnvironment, BaseModel):\n    \"\"\"External Env to integrate actual game environment\"\"\"\n\n    model_config = ConfigDict(arbitrary_types_allowed=True)\n\n    action_space: spaces.Space[ActType] = Field(default_factory=spaces.Space, exclude=True)\n    observation_space: spaces.Space[ObsType] = Field(default_factory=spaces.Space, exclude=True)\n\n    def _check_api_exist(self, rw_api: Optional[str] = None):\n        if not rw_api:\n            raise ValueError(f\"{rw_api} not exists\")\n\n    def get_all_available_apis(self, mode: str = \"read\") -> list[Any]:\n        \"\"\"get available read/write apis definition\"\"\"\n        assert mode in [\"read\", \"write\"]\n        if mode == \"read\":\n            return env_read_api_registry.get_apis()\n        else:\n            return env_write_api_registry.get_apis()\n\n    async def read_from_api(self, env_action: Union[str, EnvAPIAbstract]):\n        \"\"\"get observation from particular api of ExtEnv\"\"\"\n        if isinstance(env_action, str):\n            env_read_api = env_read_api_registry.get(api_name=env_action)[\"func\"]\n            self._check_api_exist(env_read_api)\n            if is_coroutine_func(env_read_api):\n                res = await env_read_api(self)\n            else:\n                res = env_read_api(self)","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/FoundationAgents/MetaGPT/blob/11cdf466d042aece04fc6cfd13b28e1a70341b1f/metagpt/environment/base_env.py#L45-L81","documentation":"ExtEnv._check_api_exist raises ValueError('{rw_api} not exists') when the argument is falsy — None or an empty string. Despite the message showing the value, the only failing condition is `not rw_api`; a non-empty string always passes this check (existence in the registry is enforced separately by EnvAPIRegistry.get). It is a guard against calling read/write APIs without specifying which one.","triggerScenarios":"await env.read_from_api(None) or env.read_from_api(\"\") — e.g. an EnvAPIAbstract whose api_name field defaulted to \"\", or a variable that failed to populate and defaulted to None.","commonSituations":"Constructing EnvAPIAbstract subclasses without setting api_name (it defaults to \"\"); passing a programmatically-derived api name that resolved to None from a failed lookup; refactoring call sites to pass the api name positionally where it got dropped.","solutions":["Always pass a concrete api name string: await env.read_from_api(\"api_name\") or a fully-populated EnvAPIAbstract.","If building action objects dynamically, assert api_name is non-empty before calling the env.","When accepting api names from config/user input, validate non-empty at the boundary with a clear error."],"exampleFix":"# before\nobs = await env.read_from_api(\"\")  # ValueError:  not exists\n\n# after\napi_name = \"get_map\"  \nassert api_name, \"api name must be a non-empty string\"\nobs = await env.read_from_api(api_name)","handlingStrategy":"validation","validationCode":"if not rw_api or not isinstance(rw_api, str):\n    raise ValueError(\"an api name (non-empty str) is required before calling read/write APIs\")","typeGuard":"def is_valid_api_name(name) -> bool:\n    \"\"\"True when name passes ExtEnv._check_api_exist's falsy check.\"\"\"\n    return isinstance(name, str) and bool(name)","tryCatchPattern":"try:\n    await env.read_from_api(api_name)\nexcept ValueError as e:\n    if \"not exists\" in str(e):\n        raise ValueError(\"api name was None/empty; populate api_name before calling\") from e\n    raise","preventionTips":["Set api_name explicitly on every EnvAPIAbstract subclass instead of relying on its \"\" default.","Assert the name is a non-empty string at your call boundary.","Derive api names from a validated source (config enum, registry listing), never from unvalidated user input."],"tags":["python","environment","input-validation","valueerror"],"backgroundTag":null,"analyzedSha":"11cdf466d042aece04fc6cfd13b28e1a70341b1f","analyzedAt":"2026-08-14T23:20:02.994Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}