Skip to main content
This guide covers the most common issues developers encounter when working with the TinyCloud SDK and how to resolve them.
Symptom: Creating a delegation fails with the error “Delegation failed: invalid delegatee” or similar validation error.Cause: You are using the session key DID (tc.sessionDid) instead of the primary DID (tc.did after signIn()) when specifying the delegatee. The server expects the delegatee to be the primary DID (e.g., did:pkh:eip155:{chainId}:{address} for Ethereum wallets), not session key format (did:key:z6Mk...).Solution: Use tc.did for user-to-user delegations. After signIn(), this returns the primary DID:
// Wrong - session key DID
await alice.createDelegation({ delegateDID: bob.sessionDid });

// Correct - primary DID (tc.did after signIn)
await alice.createDelegation({ delegateDID: bob.did });
See DID Formats for a detailed explanation of the primary vs session DID behavior.
Symptom: Operations fail with “space does not exist” or “space not found” errors after authentication.Cause: The space has not been created yet. This happens when autoCreateSpace is disabled, or when an extension hook (like TinyCloudStorage.afterSignIn) runs before the space creation step completes.Solution: Ensure the space exists before performing operations:
const tc = new TinyCloudWeb({
  host: 'https://api.tinycloud.xyz',
  prefix: 'my-app',
  // Ensure space is created on first sign-in
  autoCreateSpace: true,
});

await tc.signIn();
// Space is now guaranteed to exist
If you have autoCreateSpace disabled and need manual control, call ensureSpaceExists() explicitly before any data operations.
Symptom: Operations that previously worked now fail with authentication or session errors. You may see SESSION_EXPIRED or UNAUTHORIZED error codes.Cause: The session TTL has been exceeded. TinyCloud sessions have a limited lifetime for security.Solution: Detect expiry and re-authenticate:
if (tc.isSessionExpired()) {
  await tc.signIn();
}
For long-running services, use file-based session persistence and implement retry logic around session expiry. See Authentication for session persistence options.
Symptom: Import errors or runtime errors about missing WASM modules when using the SDK. Common messages include Cannot find module '@tinycloud/sdk-rs' or WebAssembly module not found.Cause: The WASM package (@tinycloud/sdk-rs) was not built before the TypeScript wrappers. The build order matters because the TypeScript packages depend on WASM artifacts that must exist first.Solution: Rebuild in the correct order:
# In the web-sdk repository root

# 1. Build WASM artifacts first
cd packages/sdk-rs
bun run build

# 2. Then build the TypeScript wrappers
cd ../..
bun run build
The required build order is:
  1. @tinycloud/sdk-rs — produces WASM artifacts
  2. @tinycloud/node-sdk-wasm — TypeScript wrapper (depends on step 1)
  3. @tinycloud/web-sdk-wasm — TypeScript wrapper (depends on step 1)
Running bun run build from the repository root without first building sdk-rs will fail. Always build WASM first.
Symptom: Calling signIn() throws an error indicating that sign-in is not available, or that a private key is required.Cause: The TinyCloud instance was initialized without a privateKey (or without a connected wallet in the Web SDK). In session-only mode, there is no wallet available to sign the SIWE message that signIn() requires.Solution: Provide a private key when initializing the Node SDK:
// This will fail - no private key for signing
const tc = new TinyCloudNode({
  host: 'https://api.tinycloud.xyz',
  prefix: 'my-app',
  // Missing: privateKey
});
await tc.signIn(); // Error: cannot sign without private key

// Correct - provide a private key
const tc = new TinyCloudNode({
  host: 'https://api.tinycloud.xyz',
  prefix: 'my-app',
  privateKey: process.env.WALLET_PRIVATE_KEY,
});
await tc.signIn(); // Works
For the Web SDK, ensure the user has connected their wallet before calling signIn().
Symptom: Creating a sub-delegation fails with a path constraint error.Cause: The path specified in the child delegation is not within the parent’s path scope. The server enforces that sub-delegations can only narrow access, never widen it.Solution: Ensure the child path is a sub-path of the parent:
// If parent delegation has path: /users/alice/*

// Valid child paths:
"/users/alice/*"              // Same scope
"/users/alice/docs/*"         // Narrower scope
"/users/alice/docs/readme.txt" // Specific file within scope

// Invalid child paths:
"/users/bob/*"    // Different user - outside parent scope
"/users/*"        // Broader than parent - cannot widen
"/admin/*"        // Unrelated path - outside parent scope
See Capabilities for the full constraint rules.
Symptom: Creating a sub-delegation fails with an expiry constraint error.Cause: The child delegation’s expiry time is later than the parent’s expiry. Sub-delegations cannot outlive the capability they derive from.Solution: Set the child expiry to be equal to or earlier than the parent:
// Parent delegation expires at timestamp 1738800000

// Get parent expiry for reference
const parentExpiry = parentDelegation.expiry;

// Create child with same or earlier expiry
await tc.createSubDelegation({
  parentDelegation,
  delegateDID: bob.did,
  expiry: new Date(Date.now() + 24 * 60 * 60 * 1000), // Must be before parent's expiry
});
When specifying expiry, ensure the absolute timestamp is before the parent’s expiry. If the parent expires in 3 days, setting an expiry 7 days from now will fail.

Still Having Issues?

If your issue is not covered here:
  1. Check the Capabilities and DID Formats concept pages for detailed explanations
  2. Verify your SDK version is up to date
  3. Review the server logs for more detailed error messages
  4. Ensure your wallet is connected to the expected network
  5. Join the TinyCloud Discord for community support