Summary
kbagent storage download-table fails with NOT_FOUND: File not found for any table on a dev branch. Root cause: the async export flow creates a Storage File scoped to the branch, but the follow-up get_file_info call queries the main project scope without a branch prefix.
Reproduction
Tested on kbagent v0.18.6, project databased (891), branch 15894.
# 1. Create branch (auto-activates)
kbagent --json branch create --project databased --name test-export-2026-04-14
# -> branch_id: 15894
# 2. Create bucket + table + upload data
kbagent --json storage create-bucket --project databased --stage in --name test-export-branch
kbagent --json storage create-table --project databased --bucket-id in.c-test-export-branch \
--name test_data --column "id:INTEGER" --column "name:STRING" --primary-key id
kbagent --json storage upload-table --project databased \
--table-id in.c-test-export-branch.test_data --file /tmp/test_data.csv
# -> imported_rows: 3, OK
# 3. Verify table exists with data
kbagent --json storage table-detail --project databased \
--table-id in.c-test-export-branch.test_data
# -> rows_count: 3, columns listed OK
# 4. Download -> FAILS
kbagent --json storage download-table --project databased \
--table-id in.c-test-export-branch.test_data --branch 15894 --output /tmp/out.csv
Returns:
{
"status": "error",
"error": {
"code": "NOT_FOUND",
"message": "Resource not found: File not found."
}
}
Same failure reproduces with storage unload-table on a branch table.
Control: download-table on a production (main) table works fine:
kbagent --json storage download-table --project databased \
--table-id in.c-data-based-ex-freelo-186733604.users --limit 5 --output /tmp/users.csv
# -> OK, file exported
Root cause
In keboola_agent_cli/client.py:
-
export_table_async (line 1167) correctly prefixes the URL with the branch:
prefix = f"/v2/storage/branch/{branch_id}" if branch_id else "/v2/storage"
# POST {prefix}/tables/{safe_id}/export-async
The Storage File is created in the branch scope.
-
get_file_info (line 1199) does not accept branch_id and always queries main:
def get_file_info(self, file_id: int) -> dict[str, Any]:
response = self._request(
"GET",
f"/v2/storage/files/{file_id}",
params={"federationToken": "1"},
)
→ Storage API returns 404 because the file was created in the branch scope, not main.
-
services/storage_service.py:604 calls client.get_file_info(file_id) without passing branch_id, so even if the client supported it, the service wouldn't use it.
Proposed fix
client.py:1199 — accept and use branch_id:
def get_file_info(self, file_id: int, branch_id: int | None = None) -> dict[str, Any]:
prefix = f"/v2/storage/branch/{branch_id}" if branch_id else "/v2/storage"
response = self._request(
"GET",
f"{prefix}/files/{file_id}",
params={"federationToken": "1"},
)
return response.json()
services/storage_service.py:604 — pass branch through:
file_detail = client.get_file_info(file_id, branch_id=branch_id)
Other file endpoints in client.py (delete_file, tag_file, untag_file, list_files) likely have the same bug — worth auditing in the same PR.
Impact
Any workflow that tries to read/export data from a dev branch via kbagent CLI fails. Currently the only workaround is to merge the branch to main first, which defeats the purpose of dev branch isolation.
Environment
- kbagent: v0.18.6
- keboola-mcp-server: v1.49.1
- Stack: connection.eu-central-1.keboola.com
- Project: 891 (data-based internal)
- Branch: 15894 (test-export-2026-04-14)
Summary
kbagent storage download-tablefails withNOT_FOUND: File not foundfor any table on a dev branch. Root cause: the async export flow creates a Storage File scoped to the branch, but the follow-upget_file_infocall queries the main project scope without a branch prefix.Reproduction
Tested on kbagent v0.18.6, project
databased(891), branch15894.Returns:
{ "status": "error", "error": { "code": "NOT_FOUND", "message": "Resource not found: File not found." } }Same failure reproduces with
storage unload-tableon a branch table.Control:
download-tableon a production (main) table works fine:kbagent --json storage download-table --project databased \ --table-id in.c-data-based-ex-freelo-186733604.users --limit 5 --output /tmp/users.csv # -> OK, file exportedRoot cause
In
keboola_agent_cli/client.py:export_table_async(line 1167) correctly prefixes the URL with the branch:The Storage File is created in the branch scope.
get_file_info(line 1199) does not acceptbranch_idand always queries main:→ Storage API returns 404 because the file was created in the branch scope, not main.
services/storage_service.py:604callsclient.get_file_info(file_id)without passingbranch_id, so even if the client supported it, the service wouldn't use it.Proposed fix
client.py:1199— accept and usebranch_id:services/storage_service.py:604— pass branch through:Other file endpoints in
client.py(delete_file,tag_file,untag_file,list_files) likely have the same bug — worth auditing in the same PR.Impact
Any workflow that tries to read/export data from a dev branch via kbagent CLI fails. Currently the only workaround is to merge the branch to main first, which defeats the purpose of dev branch isolation.
Environment