{"record":{"id":"088f7cc4e0ce8e2d","repo":"windmill-labs/windmill","slug":"expected-string-got","errorCode":null,"errorMessage":"Expected string, got {:?}","messagePattern":"Expected string, got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-store/src/resources.rs","lineNumber":4118,"sourceCode":"    db: &DB,\n    w_id: &str,\n    s: String,\n) -> std::result::Result<String, anyhow::Error> {\n    use serde_json::Value;\n    use windmill_common::db::DbWithOptAuthed;\n    let value = Value::String(s);\n    match transform_json_value(\n        &DbWithOptAuthed::from_authed(authed, db.clone(), None),\n        w_id,\n        value,\n        &None,\n        None,\n        0,\n    )\n    .await?\n    {\n        Value::String(s) => Ok(s),\n        v => Err(anyhow::anyhow!(\"Expected string, got {:?}\", v)),\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use serde_json::json;\n    use std::sync::{Arc, Mutex};\n    use windmill_common::audit::AuditAuthor;\n    use windmill_common::db::DbWithOptAuthed;\n\n    #[test]\n    fn parse_symref_head_resolves_default_branch() {\n        let out = \"ref: refs/heads/main\\tHEAD\\n7ddb8cec9a0000000000000000000000000000aa\\tHEAD\\n\";\n        assert_eq!(\n            parse_ls_remote_symref_head(out),\n            (\n                Some(\"main\".to_string()),","sourceCodeStart":4100,"sourceCodeEnd":4136,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-store/src/resources.rs#L4100-L4136","documentation":"A helper in windmill-store reads a stored value from the resource/variable store and expects the stored JSON to be a string. If the value in the store is any other JSON type (object, number, array, null), this error is thrown with a debug dump of the actual value.","triggerScenarios":"Fetching a resource/variable whose stored value is not a JSON string — e.g. the caller stored an object or number, or the path resolves to a sub-value inside a structured resource while the API contract expects a plain string.","commonSituations":"Storing a JSON object as a resource then reading it with a string-typed getter; a resource path pointing at a nested field whose type changed; migration or manual DB edits changing value shape; using variable endpoints on resources and vice versa.","solutions":["Inspect the stored value at that path (resource/variable page or DB) and confirm its actual JSON type","Use the appropriate getter for the real type (JSON/object getter) or convert the value to a string","Fix the resource/variable content so the value at that path is a plain string","Update caller code to request the value with the matching typed API","Check recent edits/migrations that could have changed the stored shape"],"exampleFix":"// before\nlet s = get_resource_value(...).await?; // fails if value is an object\n// after\nmatch get_value(...).await? {\n    Value::String(s) => Ok(s),\n    other => serde_json::from_value::<MyStruct>(other)\n        .context(\"resource is structured, not a string\"),\n}","handlingStrategy":"type-guard","validationCode":"// before calling the string getter, verify the stored shape\nlet stored: serde_json::Value = db\n    .query_opt(\"SELECT value FROM resource WHERE path = $1\", &[&path])?\n    .ok_or_else(|| anyhow::anyhow!(\"resource {path} not found\"))?\n    .get(0);\nif !stored.is_string() {\n    return Err(anyhow::anyhow!(\"resource {path} is not a plain string\"));\n}","typeGuard":"fn is_json_string(v: &serde_json::Value) -> bool {\n    matches!(v, serde_json::Value::String(_))\n}","tryCatchPattern":"match get_value_as_string(db, &workspace, &path).await {\n    Ok(s) => s,\n    Err(e) if e.to_string().starts_with(\"Expected string, got\") => {\n        // value is structured: fetch as Value and extract/serialize\n        let v = get_value(db, &workspace, &path).await?;\n        serde_json::to_string(&v)?\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Use the typed getter matching the stored shape (string getter only for strings)","Audit resources/variables after schema or migration changes","Inspect resource content in the UI before consuming it with string-typed APIs","Standardize on storing plain strings where string getters are used downstream"],"tags":["json","types","resources","store"],"backgroundTag":"unexpected-json-type","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}