SharePointVault ~/gotchas/graph ⌕ Search 404 pages, error messages, scripts…Ctrl K ★ Star
M↓ README.mdM↓ channel-created-but-its-sharepoint-folder-is-not.md
sharepoint-vault›gotchas›graph›channel-created-but-its-sharepoint-folder-is-not.mdhistoryedit on GitHub
● GOTCHAgraph· 3 min read

A Teams channel exists immediately — its folder does not

applies to: Microsoft Graph v1.0 (/teams/{id}/channels), SharePoint Online document librariesreviewed: 2026-09-23#graph#microsoft-teams#sharepoint#provisioning#channels#async

POST /teams/{team-id}/channels returns 201 and the channel shows up in Teams and in List channels right away, but the matching folder in the team site's default document library is provisioned asynchronously by Teams. Measured on a live tenant: the folder did not exist two minutes after creation, nor after ten. Anything that writes into that folder straight after creating the channel — subfolders, files, permissions — fails on a missing parent. Do not "fix" this by creating the folder yourself: a hand-made folder of the same name has no channel behind it, looks identical, and nobody notices.

POST /teams/{team-id}/channels vrátí 201 a kanál je v Teams i v List channels hned, ale odpovídající složku ve výchozí knihovně dokumentů týmového webu zakládá Teams asynchronně. Změřeno na živém tenantu: složka neexistovala dvě minuty po vytvoření kanálu, ani po deseti. Cokoli, co do ní hned po vytvoření kanálu zapisuje (podsložky, soubory, oprávnění), spadne na chybějícím rodiči. Neopravujte to tím, že složku založíte sami: ručně vytvořená složka stejného jména za sebou nemá kanál, vypadá stejně a nikdo si toho nevšimne.

Symptom

POST https://graph.microsoft.com/v1.0/teams/{team-id}/channels
{ "displayName": "Site protocols", "membershipType": "standard" }

HTTP/1.1 201 Created

The channel is usable in Teams. Meanwhile:

GET {site}/_api/web/GetFolderByServerRelativeUrl('/sites/x/Shared Documents/Site protocols')?$select=Exists

HTTP/1.1 200 OK
{ "Exists": false }

Note the 200 with Exists: false — the status code alone tells you nothing here, you have to read the value in the body.

Why

The channel (Teams service) and its folder (SharePoint) are two separate provisioning steps. Teams creates the folder lazily — commonly not until the channel's Files tab is opened for the first time. No API promises a deadline and nothing signals completion.

What to do

  1. Never create the folder yourself. It is the most tempting fix and the worst one: the folder looks right, the channel is not attached to it, and every later check ("does the structure match?") passes while the site is quietly wrong.
  2. Poll briefly, then move on. A handful of attempts (≈20 s) covers the fast path. Waiting longer blocks the whole operation and still may not succeed.
  3. Report the pending state as a sentence, not as an error. "Channel created; its folder has not appeared yet — subfolders will be added by the next run" is true and actionable. Silent success and a red failure are both lies.
  4. Skip work that depends on the folder in this pass and let an idempotent reconciliation finish it later. That is what idempotency is for.

Permissions note

Creating a channel accepts Channel.Create and — flagged by Microsoft as backward compatibility only — Directory.ReadWrite.All or Group.ReadWrite.All. Listing channels accepts Channel.ReadBasic.All and, on the same backward-compatibility footing, Directory.Read.All, Group.Read.All, Group.ReadWrite.All. Building on the legacy ones works today but can stop working without notice, so declare the least-privileged scope in your app manifest even if everything runs.

⚠ In SPFx you cannot verify the fallback on your own tenant: delegated grants belong to the tenant-wide SharePoint Online Client Extensibility Web Application Principal, so if any component ever had Channel.* approved, your call succeeds regardless of what your package requests.

Related

Was this helpful?ask or add your experience on GitHub →
Saved you an hour? A star on GitHub helps other SharePoint people find the vault.★ Star on GitHub
last reviewed: 2026-09-23last updated: 2026-09-24historyedit on GitHubview source