Stored Queries API Does Not Persist SPARQL Content

When using the REST API endpoint POST /admin/queries/stored to create stored queries on Stardog Cloud, the query metadata (name, description, database) is successfully stored, but the SPARQL query content is not persisted (stored as 0 characters).

Expected Behavior

When POSTing a JSON payload with a query field containing SPARQL content to /admin/queries/stored, the stored query should:

  1. Accept the request (HTTP 204 No Content)

  2. Store the query metadata (name, description, database, creator)

  3. Store the SPARQL query content from the query field

Actual Behavior

  1. The POST request returns HTTP 204 (success)

  2. Query metadata is stored correctly

  3. The SPARQL query content is stored as 0 characters (empty string)

  4. When retrieving the stored query via GET /admin/queries/stored/{name}, the query field is empty

Steps to Reproduce

1. Create Test Script

Save the following as test_stored_query_bug.py

#!/usr/bin/env python3
"""
Reproduces Stardog Cloud API bug where SPARQL content is not stored.
"""

import os
import requests
import json
import urllib3

# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

# Configuration
STARDOG_ENDPOINT = "https://<your-instance>.stardog.cloud:5820"
STARDOG_DATABASE = "myDatabase"
STARDOG_USERNAME = "user@example.com"
STARDOG_PASSWORD = os.environ.get("STARDOG_PASSWORD", "your_password")

def main():
    print("="*70)
    print("Stardog Cloud Stored Query API Bug Reproduction")
    print("="*70)
    
    # Create session
    session = requests.Session()
    session.verify = False
    session.auth = (STARDOG_USERNAME, STARDOG_PASSWORD)
    
    # Define a simple test query
    query_name = "test_bug_reproduction"
    sparql_query = """PREFIX ocm: <http://www.w3.org/2019/05/ocm#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?risk ?riskScore ?riskLevel
WHERE {
  ?risk a ocm:Risk ;
        ocm:riskScore ?riskScore ;
        ocm:riskLevel ?riskLevel .
}
ORDER BY DESC(?riskScore)
LIMIT 10"""
    
    # Prepare payload
    payload = {
        "name": query_name,
        "database": STARDOG_DATABASE,
        "query": sparql_query,
        "shared": True,
        "description": "Test query to reproduce API bug",
        "creator": STARDOG_USERNAME
    }
    
    print(f"\n1. DELETING existing query (if exists)...")
    delete_url = f"{STARDOG_ENDPOINT}/admin/queries/stored/{query_name}"
    delete_response = session.delete(delete_url)
    print(f"   Status: {delete_response.status_code}")
    
    print(f"\n2. CREATING stored query via POST...")
    print(f"   Endpoint: {STARDOG_ENDPOINT}/admin/queries/stored")
    print(f"   Query name: {query_name}")
    print(f"   SPARQL length: {len(sparql_query)} characters")
    print(f"   Payload keys: {list(payload.keys())}")
    
    create_url = f"{STARDOG_ENDPOINT}/admin/queries/stored"
    create_response = session.post(
        create_url,
        json=payload,
        headers={'Content-Type': 'application/json'}
    )
    
    print(f"   Response status: {create_response.status_code}")
    print(f"   Response body: {create_response.text[:200] if create_response.text else '(empty)'}")
    
    if create_response.status_code not in [200, 201, 204]:
        print(f"\n❌ POST failed with status {create_response.status_code}")
        return
    
    print(f"   ✓ POST successful (HTTP {create_response.status_code})")
    
    print(f"\n3. RETRIEVING stored query via GET...")
    get_url = f"{STARDOG_ENDPOINT}/admin/queries/stored/{query_name}"
    get_response = session.get(
        get_url,
        headers={'Accept': 'application/json'}
    )
    
    print(f"   Status: {get_response.status_code}")
    
    if get_response.status_code != 200:
        print(f"   ❌ Failed to retrieve query")
        return
    
    stored_query = get_response.json()
    stored_sparql = stored_query.get('query', '')
    
    print(f"\n4. VERIFICATION:")
    print(f"   Query name: {stored_query.get('name')}")
    print(f"   Database: {stored_query.get('database')}")
    print(f"   Description: {stored_query.get('description')}")
    print(f"   Creator: {stored_query.get('creator')}")
    print(f"   Shared: {stored_query.get('shared')}")
    print(f"   Stored SPARQL length: {len(stored_sparql)} characters")
    
    print(f"\n5. RESULT:")
    if len(stored_sparql) == 0:
        print(f"   ❌ BUG CONFIRMED: SPARQL content is EMPTY (0 characters)")
        print(f"   Expected: {len(sparql_query)} characters")
        print(f"   Actual: 0 characters")
        print(f"\n   The API accepted the payload but did NOT persist the 'query' field.")
    else:
        print(f"   ✓ SPARQL content is stored ({len(stored_sparql)} characters)")
        if stored_sparql == sparql_query:
            print(f"   ✓ Content matches original query")
        else:
            print(f"   ⚠️  Content differs from original query")
    
    print(f"\n" + "="*70)

if __name__ == "__main__":
    main()

3. Expected Output

======================================================================
Stardog Cloud Stored Query API Bug Reproduction
======================================================================

1. DELETING existing query (if exists)...
   Status: 204

2. CREATING stored query via POST...
   Endpoint: https://<your-instance>.stardog.cloud:5820/admin/queries/stored
   Query name: test_bug_reproduction
   SPARQL length: 234 characters
   Payload keys: ['name', 'database', 'query', 'shared', 'description', 'creator']
   Response status: 204
   Response body: (empty)
   ✓ POST successful (HTTP 204)

3. RETRIEVING stored query via GET...
   Status: 200

4. VERIFICATION:
   Query name: test_bug_reproduction
   Database: myDatabase
   Description: Test query to reproduce API bug
   Creator: user@example.com
   Shared: True
   Stored SPARQL length: 0 characters

5. RESULT:
   ❌ BUG CONFIRMED: SPARQL content is EMPTY (0 characters)
   Expected: 234 characters
   Actual: 0 characters

   The API accepted the payload but did NOT persist the 'query' field.

======================================================================

Additional Information

Payload Structure Used

{
  "name": "test_bug_reproduction",
  "database": "myDatabase",
  "query": "PREFIX ex: <http://example.org/>\n\nSELECT ?s ?p ?o\nWHERE {\n  ?s ?p ?o .\n}\nLIMIT 10",
  "shared": true,
  "description": "Test query to reproduce API bug",
  "creator": "user@example.com"
}

API Endpoints Tested

  • POST https://<instance>.stardog.cloud:5820/admin/queries/stored - Returns 204, but doesn't store SPARQL

  • GET https://<instance>.stardog.cloud:5820/admin/queries/stored/{name} - Returns metadata but empty query field

  • DELETE https://<instance>.stardog.cloud:5820/admin/queries/stored/{name} - Works correctly

What Works

  • Query metadata (name, description, database, creator, shared) is stored correctly

  • DELETE endpoint works correctly

  • GET endpoint returns the stored query metadata

  • The query appears in the list of stored queries

What Doesn't Work

  • The query field in the JSON payload is not persisted

  • Retrieved stored queries have an empty SPARQL query string (0 characters)

  • This makes stored queries unusable via the API

mpact

  • Cannot automate stored query deployment via REST API

  • CI/CD pipelines cannot manage stored queries programmatically

  • Manual intervention required for every query update

  • Inconsistent behavior between API and UI

Questions

  1. Is this a known limitation of Stardog Cloud's REST API?

  2. Is there an alternative API endpoint or method to store SPARQL content?

  3. Is there a timeline for fixing this issue?

  4. Are there any undocumented API parameters or headers required?