• Townie
    AI
  • Blog
  • Docs
  • Pricing
  • We’re hiring!
Log inSign up
c15r

c15r

ContextualLite

Public
Like
ContextualLite
Home
Code
16
CHANGELOG.md
MIGRATION.md
README.md
auth-manager.ts
claude-desktop-config.json
deploy.ts
example-s3-script.js
example.env
files-store.ts
H
index.ts
kv-store.ts
mcp-config.json
mcp-handler.ts
mcp-http-client.js
package.json
tools.ts
Branches
2
Pull requests
Remixes
History
Environment variables
7
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Sign up now
Code
/
MIGRATION.md
Code
/
MIGRATION.md
Search
6/12/2025
Viewing readonly version of main branch: v238
View latest version
MIGRATION.md

Migration Guide: KV Store Schema Update

Overview

This migration addresses the "Query key condition not supported" error by restructuring the DynamoDB table schema from a single partition key to a composite key structure.

What Changed

Before (Broken)

  • Partition Key: pk containing ${namespace}:${userKey}
  • Query Pattern: Used invalid begins_with(pk, :prefix) in KeyConditionExpression

After (Fixed)

  • Partition Key: pk containing just the namespace
  • Sort Key: sk containing the user key
  • Query Pattern: Uses valid pk = :namespace AND begins_with(sk, :prefix)

Migration Steps

Option 1: Create New Table (Recommended)

  1. Create a new DynamoDB table with the correct schema:

    aws dynamodb create-table \ --table-name your-new-table-name \ --attribute-definitions \ AttributeName=pk,AttributeType=S \ AttributeName=sk,AttributeType=S \ --key-schema \ AttributeName=pk,KeyType=HASH \ AttributeName=sk,KeyType=RANGE \ --billing-mode PAY_PER_REQUEST
  2. Update your environment variable:

    DYNAMODB_TABLE=your-new-table-name
  3. Optional: Migrate existing data using the migration script below.

Option 2: Migrate Existing Table Data

If you have existing data in the old format, use this migration script:

// Migration script to convert old format to new format async function migrateKVData() { const AWS = require('@aws-sdk/client-dynamodb'); const { DynamoDBDocumentClient, ScanCommand, PutCommand, DeleteCommand } = require('@aws-sdk/lib-dynamodb'); const client = DynamoDBDocumentClient.from(new AWS.DynamoDBClient({ region: 'us-east-1', credentials: { accessKeyId: 'your-access-key', secretAccessKey: 'your-secret-key' } })); const oldTableName = 'your-old-table'; const newTableName = 'your-new-table'; // Scan all items from old table const scanResult = await client.send(new ScanCommand({ TableName: oldTableName })); for (const item of scanResult.Items || []) { // Parse old format: pk = "namespace:userkey" const oldPk = item.pk; const colonIndex = oldPk.indexOf(':'); if (colonIndex === -1) continue; // Skip invalid items const namespace = oldPk.substring(0, colonIndex); const userKey = oldPk.substring(colonIndex + 1); // Create new format item const newItem = { pk: namespace, // Just the namespace sk: userKey, // Just the user key data: item.data, created: item.created, updated: item.updated }; if (item.ttl) { newItem.ttl = item.ttl; } // Put item in new table await client.send(new PutCommand({ TableName: newTableName, Item: newItem })); console.log(`Migrated: ${namespace}:${userKey}`); } console.log('Migration completed!'); }

Data Structure Comparison

Old Format (Broken)

{ "pk": "user123:settings", "data": {"theme": "dark"}, "created": "2024-01-01T00:00:00Z", "updated": "2024-01-01T00:00:00Z" }

New Format (Fixed)

{ "pk": "user123", "sk": "settings", "data": {"theme": "dark"}, "created": "2024-01-01T00:00:00Z", "updated": "2024-01-01T00:00:00Z" }

Benefits of New Structure

  1. Correct DynamoDB Usage: Uses proper KeyConditionExpression syntax
  2. Efficient Queries: Leverages DynamoDB's composite key capabilities
  3. Better Performance: Query operations are more efficient than Scan
  4. Namespace Isolation: Each user's data is efficiently partitioned
  5. Prefix Matching: Supports efficient prefix queries within namespaces

Verification

After migration, test the KV operations:

# Test kv-list (this was failing before) curl -X POST https://your-val-town-url.web.val.run/mcp \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-aws-secret-access-key" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "kv-list", "arguments": { "prefix": "config" } }, "id": 1 }'

If this returns results without the "Query key condition not supported" error, the migration was successful.

Rollback Plan

If you need to rollback:

  1. Keep the old table until you're confident the new structure works
  2. Update the DYNAMODB_TABLE environment variable back to the old table name
  3. Revert the code changes in kv-store.ts

Support

If you encounter issues during migration:

  1. Check that your new table has the correct schema (pk as HASH, sk as RANGE)
  2. Verify your AWS permissions include Query operations
  3. Test with a simple kv-put and kv-get operation first
  4. Check the CloudWatch logs for detailed error messages
FeaturesVersion controlCode intelligenceCLI
Use cases
TeamsAI agentsSlackGTM
ExploreDocsShowcaseTemplatesNewestTrendingAPI examplesNPM packages
PricingNewsletterBlogAboutCareers
We’re hiring!
Brandhi@val.townStatus
X (Twitter)
Discord community
GitHub discussions
YouTube channel
Bluesky
Terms of usePrivacy policyAbuse contact
© 2025 Val Town, Inc.